Skip to content

Commit

Permalink
Initial code commit
Browse files Browse the repository at this point in the history
  • Loading branch information
SteveDesmond-ca committed Oct 14, 2021
1 parent 00f43ea commit 169f0c3
Show file tree
Hide file tree
Showing 24 changed files with 1,262 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -348,3 +348,6 @@ MigrationBackup/

# Ionide (cross platform F# VS Code tools) working folder
.ionide/

.idea/
.env
48 changes: 48 additions & 0 deletions GitHubLabelSync.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitHubLabelSync", "src\GitHubLabelSync.csproj", "{2F338383-5B7C-4398-A375-E005DFD09A3F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitHubLabelSync.Tests", "test\GitHubLabelSync.Tests.csproj", "{CBF71974-EAE3-49DD-A8BC-0DFDC2D9FC26}"
EndProject
Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2F338383-5B7C-4398-A375-E005DFD09A3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2F338383-5B7C-4398-A375-E005DFD09A3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2F338383-5B7C-4398-A375-E005DFD09A3F}.Debug|x64.ActiveCfg = Debug|Any CPU
{2F338383-5B7C-4398-A375-E005DFD09A3F}.Debug|x64.Build.0 = Debug|Any CPU
{2F338383-5B7C-4398-A375-E005DFD09A3F}.Debug|x86.ActiveCfg = Debug|Any CPU
{2F338383-5B7C-4398-A375-E005DFD09A3F}.Debug|x86.Build.0 = Debug|Any CPU
{2F338383-5B7C-4398-A375-E005DFD09A3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2F338383-5B7C-4398-A375-E005DFD09A3F}.Release|Any CPU.Build.0 = Release|Any CPU
{2F338383-5B7C-4398-A375-E005DFD09A3F}.Release|x64.ActiveCfg = Release|Any CPU
{2F338383-5B7C-4398-A375-E005DFD09A3F}.Release|x64.Build.0 = Release|Any CPU
{2F338383-5B7C-4398-A375-E005DFD09A3F}.Release|x86.ActiveCfg = Release|Any CPU
{2F338383-5B7C-4398-A375-E005DFD09A3F}.Release|x86.Build.0 = Release|Any CPU
{CBF71974-EAE3-49DD-A8BC-0DFDC2D9FC26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CBF71974-EAE3-49DD-A8BC-0DFDC2D9FC26}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CBF71974-EAE3-49DD-A8BC-0DFDC2D9FC26}.Debug|x64.ActiveCfg = Debug|Any CPU
{CBF71974-EAE3-49DD-A8BC-0DFDC2D9FC26}.Debug|x64.Build.0 = Debug|Any CPU
{CBF71974-EAE3-49DD-A8BC-0DFDC2D9FC26}.Debug|x86.ActiveCfg = Debug|Any CPU
{CBF71974-EAE3-49DD-A8BC-0DFDC2D9FC26}.Debug|x86.Build.0 = Debug|Any CPU
{CBF71974-EAE3-49DD-A8BC-0DFDC2D9FC26}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CBF71974-EAE3-49DD-A8BC-0DFDC2D9FC26}.Release|Any CPU.Build.0 = Release|Any CPU
{CBF71974-EAE3-49DD-A8BC-0DFDC2D9FC26}.Release|x64.ActiveCfg = Release|Any CPU
{CBF71974-EAE3-49DD-A8BC-0DFDC2D9FC26}.Release|x64.Build.0 = Release|Any CPU
{CBF71974-EAE3-49DD-A8BC-0DFDC2D9FC26}.Release|x86.ActiveCfg = Release|Any CPU
{CBF71974-EAE3-49DD-A8BC-0DFDC2D9FC26}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# GitHubLabelSync
# GitHub Label Sync
Synchronize GitHub issue labels across repositories
41 changes: 41 additions & 0 deletions src/App.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using System.Threading.Tasks;

namespace GitHubLabelSync
{
public class App
{
private readonly ISynchronizer _sync;
private readonly Action<string> _setStatus;
private readonly Action<string> _log;

public App(ISynchronizer sync, Action<string> setStatus, Action<string> log)
{
_sync = sync;
_setStatus = setStatus;
_log = log;
}

public async Task Run(Settings settings)
{
_setStatus($"Starting...");

var account = await _sync.GetAccount(settings.Name);
_log(string.Empty);

var repos = await _sync.GetRepositories(account);
_log(string.Empty);

var labels = await _sync.GetAccountLabels(account);
_log(string.Empty);

foreach (var repo in repos)
{
await _sync.SyncRepo(repo, settings, labels);
_log(string.Empty);
}

_log("Done!");
}
}
}
35 changes: 35 additions & 0 deletions src/Command.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using System.Threading.Tasks;
using Spectre.Console;
using Spectre.Console.Cli;

namespace GitHubLabelSync
{
public class Command : AsyncCommand<Settings>
{
private readonly IAnsiConsole _console;

public Command(IAnsiConsole console)
=> _console = console;

public override async Task<int> ExecuteAsync(CommandContext context, Settings settings)
{
try
{
await _console.Status().StartAsync("Running...", Run(settings));
return 0;
}
catch (Exception e)
{
_console.WriteException(e);
return 1;
}
}

private Func<StatusContext, Task> Run(Settings settings)
=> async ctx
=> await Factory
.App(settings.APIKey, s => _console.WriteLine(s), s => ctx.Status(s))
.Run(settings);
}
}
20 changes: 20 additions & 0 deletions src/Factory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Reflection;
using Octokit;

namespace GitHubLabelSync
{
public static class Factory
{
public static App App(string apiKey, Action<string> setStatus, Action<string> log)
{
var name = Assembly.GetExecutingAssembly().GetName().Name;
var value = new ProductHeaderValue(name);
var client = new GitHubClient(value) { Credentials = new Credentials(apiKey) };

var gitHub = new GitHub(client, setStatus, log);
var sync = new Synchronizer(gitHub, new Random(), setStatus, log);
return new App(sync, setStatus, log);
}
}
}
113 changes: 113 additions & 0 deletions src/GitHub.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Octokit;

namespace GitHubLabelSync
{
public class GitHub : IGitHub
{
private readonly IGitHubClient _client;
private readonly Action<string> _setStatus;
private readonly Action<string> _log;

public GitHub(IGitHubClient client, Action<string> setStatus, Action<string> log)
{
_client = client;
_setStatus = setStatus;
_log = log;
}

public async Task<Account> GetOrganization(string name)
{
_setStatus($"Finding organization for {name}...");
var account = await _client.Organization.Get(name);
_log($"Organization ID for {name}: {account.Id}");
return account;
}

public async Task<Account> GetUser(string name)
{
_setStatus($"Finding user for {name}...");
var account = await _client.User.Get(name);
_log($"User ID for {name}: {account.Id}");
return account;
}

public async Task<IReadOnlyList<Repository>> GetRepositoriesForOrganization(Account account)
{
_setStatus($"Finding repositories for {account.Login}...");
var repos = await _client.Repository.GetAllForOrg(account.Login);
var repoNames = string.Join(", ", repos.Select(l => l.Name));
_log($"{repos.Count} repositories for {account.Login}: {repoNames}");
return repos;
}

public async Task<IReadOnlyList<Repository>> GetRepositoriesForUser(Account account)
{
_setStatus($"Finding repositories for {account.Login}...");
var repos = await _client.Repository.GetAllForUser(account.Login);
var repoNames = string.Join(", ", repos.Select(l => l.Name));
_log($"{repos.Count} repositories for {account.Login}: {repoNames}");
return repos;
}

public async Task<Repository> CreateTempRepoForOrganization(Account account, string repoName)
{
_setStatus($"Creating temp repository {repoName}...");
var newRepo = new NewRepository(repoName) { Private = true };
var repo = await _client.Repository.Create(account.Login, newRepo);
_log($"Created temp repository {repoName}");
return repo;
}

public async Task<Repository> CreateTempRepoForUser(Account account, string repoName)
{
_setStatus($"Creating temp repository {repoName}...");
var newRepo = new NewRepository(repoName) { Private = true };
var repo = await _client.Repository.Create(newRepo);
_log($"Created temp repository {repoName}");
return repo;
}

public async Task DeleteTempRepo(Account account, string repoName)
{
_setStatus($"Deleting temp repository {repoName}...");
await _client.Repository.Delete(account.Login, repoName);
_log($"Deleted temp repository {repoName}");
}

public async Task<IReadOnlyList<Label>> GetLabels(Repository repo)
{
_setStatus($"Finding labels for {repo.Name}...");
var repoLabels = await _client.Issue.Labels.GetAllForRepository(repo.Id);
var repoLabelNames = string.Join(", ", repoLabels.Select(l => l.Name));
_log($"{repoLabels.Count,2} labels : {repoLabelNames}");
return repoLabels;
}

public async Task AddLabel(Repository repo, Label label)
{
_setStatus($"Adding {label.Name} to {repo.Name}...");
var newLabel = new NewLabel(label.Name, label.Color) { Description = label.Description };
await _client.Issue.Labels.Create(repo.Id, newLabel);
_log($"Added {label.Name}");
}

public async Task EditLabel(Repository repo, Label label)
{
_setStatus($"Editing {label.Name} in {repo.Name}...");
var newLabel = new LabelUpdate(label.Name, label.Color) { Description = label.Description };
await _client.Issue.Labels.Update(repo.Id, label.Name, newLabel);
_log($"Edited {label.Name}");
}

public async Task DeleteLabel(Repository repo, Label label)
{
_setStatus($"Deleting {label.Name} from {repo.Name}...");
await _client.Issue.Labels.Delete(repo.Id, label.Name);
_log($"Deleted {label.Name}");
}
}
}
25 changes: 25 additions & 0 deletions src/GitHubLabelSync.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Version>0.1.0</Version>
<OutputType>Exe</OutputType>
<PackAsTool>true</PackAsTool>
<ToolCommandName>sync-labels</ToolCommandName>
<TargetFramework>net5.0</TargetFramework>
<Description>Synchronize GitHub issue labels across repositories</Description>
<Authors>ecoAPM LLC</Authors>
<Company>ecoAPM LLC</Company>
<Copyright>ecoAPM LLC</Copyright>
<Product>GitHubLabelSync</Product>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageProjectUrl>https://github.com/ecoAPM/GitHubLabelSync</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryUrl>https://github.com/ecoAPM/GitHubLabelSync</RepositoryUrl>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Octokit" Version="0.50.0" />
<PackageReference Include="Spectre.Console" Version="0.42.0" />
</ItemGroup>
</Project>
24 changes: 24 additions & 0 deletions src/IGitHub.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Octokit;

namespace GitHubLabelSync
{
public interface IGitHub
{
Task<Account> GetOrganization(string name);
Task<Account> GetUser(string name);

Task<IReadOnlyList<Repository>> GetRepositoriesForOrganization(Account account);
Task<IReadOnlyList<Repository>> GetRepositoriesForUser(Account account);

Task<Repository> CreateTempRepoForOrganization(Account account, string repoName);
Task<Repository> CreateTempRepoForUser(Account account, string repoName);
Task DeleteTempRepo(Account account, string repoName);

Task<IReadOnlyList<Label>> GetLabels(Repository repo);
Task AddLabel(Repository repo, Label label);
Task EditLabel(Repository repo, Label label);
Task DeleteLabel(Repository repo, Label label);
}
}
14 changes: 14 additions & 0 deletions src/ISynchronizer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Octokit;

namespace GitHubLabelSync
{
public interface ISynchronizer
{
Task<Account> GetAccount(string name);
Task<IEnumerable<Repository>> GetRepositories(Account account);
Task<IReadOnlyList<Label>> GetAccountLabels(Account account);
Task SyncRepo(Repository repo, Settings settings, IReadOnlyList<Label> accountLabels);
}
}
11 changes: 11 additions & 0 deletions src/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Threading.Tasks;
using Spectre.Console.Cli;

namespace GitHubLabelSync
{
public static class Program
{
public static async Task Main(string[] args)
=> await new CommandApp<Command>().RunAsync(args);
}
}
Loading

0 comments on commit 169f0c3

Please sign in to comment.