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