Add project files.
This commit is contained in:
13
README.md
Normal file
13
README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# GitHub Repository Bookup Tool
|
||||
|
||||
This is a lightweight command line interface for backing up a GitHub user's repositories. Depending on permissions provided
|
||||
during authentication, the tool can backup public and private repositories.
|
||||
|
||||
The tool is writting in C# and uses the Octokit.net library to interact with the GitHub API.
|
||||
|
||||
## Usage
|
||||
|
||||
The tool is a command line interface. It can be run from the command line or from a batch file. The tool requires a GitHub
|
||||
Personal Access Token to be provided as a command line argument. The token can be generated from the GitHub website. It is
|
||||
recommended that the user only provide the minimum permissions required to backup the repositories. GitHub provides a fine-grained
|
||||
access token generator that makes this very simple.
|
||||
25
repo-backup-util.sln
Normal file
25
repo-backup-util.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.8.34309.116
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "repo-backup-util", "repo-backup-util\repo-backup-util.csproj", "{352652F3-958B-416B-B5F5-CDC36B0AA0C4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{352652F3-958B-416B-B5F5-CDC36B0AA0C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{352652F3-958B-416B-B5F5-CDC36B0AA0C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{352652F3-958B-416B-B5F5-CDC36B0AA0C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{352652F3-958B-416B-B5F5-CDC36B0AA0C4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {46CA2A1B-A03D-4D97-9DDF-4BCABF53C54A}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
30
repo-backup-util/Program.cs
Normal file
30
repo-backup-util/Program.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
// See https://aka.ms/new-console-template for more information
|
||||
using Octokit;
|
||||
using RepoBackupUtil.Lib;
|
||||
|
||||
static async Task Main()
|
||||
{
|
||||
// initialize our github client
|
||||
ProductHeaderValue productHeaderValue = new("repo-backup-util");
|
||||
GitHubClient github = new(productHeaderValue);
|
||||
|
||||
// check for user with received input
|
||||
string username = GitHub.SetCredentialsToken(github);
|
||||
User user = await GitHub.GetUser(username, github);
|
||||
|
||||
// get all repos for user
|
||||
IEnumerable<Repository> repos = await GitHub.GetRepos(github) ?? throw new Exception("No repos found");
|
||||
|
||||
// organize and ensure all repositories are unique
|
||||
HashSet<Repository> uniqueRepos = GitHub.GetUniqueRepos(repos);
|
||||
|
||||
// derive repository count and clone urls
|
||||
var privateRepos = uniqueRepos.Where(r => r.Private);
|
||||
var publicRepos = uniqueRepos.Where(r => !r.Private);
|
||||
|
||||
Console.WriteLine($"Found {privateRepos.Count()} private repos and {publicRepos.Count()} public repos.");
|
||||
|
||||
var cloneUrls = uniqueRepos.Select(r => r.CloneUrl);
|
||||
}
|
||||
|
||||
await Main();
|
||||
85
repo-backup-util/lib/GitHub.cs
Normal file
85
repo-backup-util/lib/GitHub.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using Octokit;
|
||||
|
||||
namespace RepoBackupUtil.Lib
|
||||
{
|
||||
public static class GitHub
|
||||
{
|
||||
public static string SetCredentialsToken(GitHubClient github)
|
||||
{
|
||||
Console.WriteLine("Please enter your Github Personal Access Token: ");
|
||||
string? token = Console.ReadLine();
|
||||
|
||||
if (token == null)
|
||||
{
|
||||
Console.WriteLine("Received invalid input. Try again:");
|
||||
return SetCredentialsToken(github);
|
||||
}
|
||||
else
|
||||
{
|
||||
AuthenticationType authType = AuthenticationType.Bearer;
|
||||
Credentials auth = new(token, authType);
|
||||
github.Credentials = auth;
|
||||
Console.WriteLine("Successfully authenticated with GitHub.");
|
||||
return github.User.Current().Result.Login;
|
||||
}
|
||||
}
|
||||
|
||||
public static string SetOAuthCredentials(GitHubClient github)
|
||||
{
|
||||
Console.WriteLine("Provide OAuth Client Secret: ");
|
||||
string? clientSecret = Console.ReadLine();
|
||||
|
||||
if (clientSecret == null)
|
||||
{
|
||||
Console.WriteLine("Received invalid input. Try again:");
|
||||
return SetOAuthCredentials(github);
|
||||
}
|
||||
else
|
||||
{
|
||||
Credentials auth = new(clientSecret, AuthenticationType.Oauth);
|
||||
github.Credentials = auth;
|
||||
Console.WriteLine("Successfully authenticated with GitHub.");
|
||||
return github.User.Current().Result.Login;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<User> GetUser(string username, GitHubClient github)
|
||||
{
|
||||
Console.WriteLine("Checking for user...");
|
||||
User? user = await github.User.Get(username);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
Console.WriteLine("User does not exist");
|
||||
string newUsername = SetCredentialsToken(github);
|
||||
return await GetUser(newUsername, github);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Found user {user.Login}. Loading repos...");
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<IReadOnlyList<Repository>?> GetRepos(GitHubClient github)
|
||||
{
|
||||
Console.WriteLine("Loading repos...");
|
||||
var repos = await github.Repository.GetAllForCurrent();
|
||||
return repos;
|
||||
}
|
||||
|
||||
public static HashSet<Repository> GetUniqueRepos(IEnumerable<Repository> repos)
|
||||
{
|
||||
HashSet<Repository> uniqueRepos = [];
|
||||
int i = 0;
|
||||
|
||||
foreach (var repo in repos)
|
||||
{
|
||||
bool added = uniqueRepos.Add(repo);
|
||||
Console.WriteLine($"{++i} - {(added ? "added" : null)}{repo.Name} - {(repo.Private ? "Private" : "Public")}");
|
||||
}
|
||||
|
||||
return uniqueRepos;
|
||||
}
|
||||
}
|
||||
}
|
||||
10
repo-backup-util/lib/Volumes.cs
Normal file
10
repo-backup-util/lib/Volumes.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace RepoBackupUtil.Lib
|
||||
{
|
||||
public static class Volumes
|
||||
{
|
||||
public static IEnumerable<DriveInfo> GetVolumes()
|
||||
{
|
||||
return DriveInfo.GetDrives();
|
||||
}
|
||||
}
|
||||
}
|
||||
15
repo-backup-util/repo-backup-util.csproj
Normal file
15
repo-backup-util/repo-backup-util.csproj
Normal file
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RootNamespace>RepoBackupUtil</RootNamespace>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Octokit" Version="9.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user