Last active
July 8, 2021 14:42
-
-
Save BlythMeister/5b44c826f97119efa141b7d043ef9116 to your computer and use it in GitHub Desktop.
Fork Sync
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Query Kind="Program"> | |
<NuGetReference>Octokit</NuGetReference> | |
<Namespace>Octokit</Namespace> | |
<Namespace>System.Threading.Tasks</Namespace> | |
</Query> | |
GitHubClient githubClient; | |
/* START SETTINGS */ | |
string githubToken = "[TOKEN]"; | |
string githubUserName = "BlythMeister"; | |
string basePath = "F:\\ForkSync"; | |
/* END SETTINGS */ | |
async Task Main() | |
{ | |
githubClient = new GitHubClient(new ProductHeaderValue("ForkSync")); | |
githubClient.Credentials = new Credentials(githubUserName, githubToken); | |
Console.WriteLine($"Base Directory For Sync: {basePath}"); | |
Directory.CreateDirectory(basePath); | |
try | |
{ | |
var forks = await GetForks(); | |
Console.WriteLine($"Found {forks.Count()} to update"); | |
foreach (var fork in forks) | |
{ | |
var repoDir = Path.Combine(basePath, fork.Name); | |
try | |
{ | |
Console.WriteLine("-----------------------------"); | |
try | |
{ | |
Console.WriteLine($"Syncing branch {fork.ForkDefaultBranch} to {fork.UpstreamDefaultBranch} for repo {fork.Name}"); | |
if(!Directory.Exists(repoDir)) | |
{ | |
RunGit(basePath, $"clone --origin fork --quiet {fork.ForkSsh} {repoDir}"); | |
RunGit(repoDir, $"remote add upstream {fork.UpstreamSsh}"); | |
} | |
RunGit(repoDir, $"fetch upstream --quiet"); | |
RunGit(repoDir, $"merge upstream/{fork.UpstreamDefaultBranch} --ff --quiet"); | |
RunGit(repoDir, $"push --quiet"); | |
} | |
catch (Exception e) | |
{ | |
Console.WriteLine($"Error on git sync fork {fork.Name} - {e.Message}"); | |
} | |
try | |
{ | |
Console.WriteLine("Removing Fully Merged Branches"); | |
await RemoveFullyMergedBranches(fork.Id, fork.ForkDefaultBranch); | |
} | |
catch (Exception e) | |
{ | |
Console.WriteLine($"Error on remove branches on fork {fork.Name} - {e.Message}"); | |
} | |
} | |
catch (Exception e) | |
{ | |
Console.WriteLine($"Error on fork {fork.Name} - {e.Message}"); | |
} | |
} | |
} | |
catch (Exception e) | |
{ | |
Console.WriteLine("Error Occured"); | |
Console.WriteLine(e.ToString()); | |
} | |
} | |
private async Task<List<(long Id, string Name, string UpstreamDefaultBranch, string UpstreamSsh, string ForkDefaultBranch, string ForkSsh)>> GetForks() | |
{ | |
var currentUser = await githubClient.User.Current(); | |
var currentUserRepos = await githubClient.Repository.GetAllForCurrent(); | |
var repos = new List<(long Id, string Name, string UpstreamDefaultBranch, string UpstreamSsh, string ForkDefaultBranch, string ForkSsh)>(); | |
foreach (var repo in currentUserRepos.Where(x => x.Fork && x.Owner.Id == currentUser.Id)) | |
{ | |
var repoFull = await githubClient.Repository.Get(repo.Id); | |
repos.Add((repo.Id, repo.Name, repoFull.Parent.DefaultBranch, repoFull.Parent.SshUrl, repoFull.DefaultBranch, repo.SshUrl)); | |
} | |
return repos; | |
} | |
private async Task RemoveFullyMergedBranches(long repoId, string defaultBranchName) | |
{ | |
var repo = await githubClient.Repository.Get(repoId); | |
var branches = await githubClient.Repository.Branch.GetAll(repoId); | |
var defaultBranch = branches.FirstOrDefault(x => x.Name == defaultBranchName); | |
if (defaultBranch != null) | |
{ | |
Console.WriteLine("-----------------------------"); | |
Console.WriteLine("Cleaning Branches On Fork"); | |
foreach (var branch in branches.Where(x => x.Name != defaultBranchName && !x.Protected)) | |
{ | |
var commitDetails = await githubClient.Repository.Commit.Get(repoId, branch.Commit.Sha); | |
if (commitDetails.Author.Id != repo.Owner.Id && commitDetails.Commit.Author.Date < DateTime.UtcNow.AddDays(-90)) | |
{ | |
Console.WriteLine($"Removing branch {branch.Name} (Last commit over 90 days ago & not by me)"); | |
await githubClient.Git.Reference.Delete(repo.Id, $"heads/{branch.Name}"); | |
} | |
else | |
{ | |
var compare = await githubClient.Repository.Commit.Compare(repoId, defaultBranch.Commit.Sha, branch.Commit.Sha); | |
if (compare.AheadBy == 0) | |
{ | |
Console.WriteLine($"Removing branch {branch.Name} (Fully merged)"); | |
await githubClient.Git.Reference.Delete(repo.Id, $"heads/{branch.Name}"); | |
} | |
else | |
{ | |
var differencesInFilesFound = false; | |
foreach (var compareFile in compare.Files) | |
{ | |
if (compareFile.Additions > 0 || compareFile.Deletions > 0) | |
{ | |
differencesInFilesFound = true; | |
break; | |
} | |
} | |
if (differencesInFilesFound) | |
{ | |
Console.WriteLine($"Unmerged commits on {branch.Name}"); | |
} | |
else | |
{ | |
Console.WriteLine($"Removing branch {branch.Name} (No File Changes)"); | |
await githubClient.Git.Reference.Delete(repo.Id, $"heads/{branch.Name}"); | |
} | |
} | |
} | |
} | |
} | |
} | |
private void RunGit(string workingDirectory, string args, bool ignoreError = false) | |
{ | |
RunCommand(workingDirectory, "git", args, ignoreError); | |
} | |
private void RunCommand(string workingDirectory, string fileName, string args, bool ignoreError) | |
{ | |
Process process = new Process(); | |
Console.WriteLine("-----------------------------"); | |
Console.WriteLine($"WorkingDirectory: {workingDirectory}"); | |
Console.WriteLine($"Exec: {fileName} {args}"); | |
try | |
{ | |
process.StartInfo.FileName = fileName; | |
process.StartInfo.WorkingDirectory = workingDirectory; | |
process.StartInfo.Arguments = args; | |
process.StartInfo.RedirectStandardError = true; | |
process.StartInfo.RedirectStandardOutput = true; | |
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; | |
process.StartInfo.CreateNoWindow = true; | |
process.StartInfo.UseShellExecute = false; | |
process.EnableRaisingEvents = false; | |
process.OutputDataReceived += (sender, eventArgs) => WriteConsoleOutput("stdOut", eventArgs); | |
process.ErrorDataReceived += (sender, eventArgs) => WriteConsoleOutput("stdErr", eventArgs); | |
process.Start(); | |
process.BeginOutputReadLine(); | |
process.BeginErrorReadLine(); | |
process.WaitForExit(); | |
if (process.ExitCode == 0) | |
{ | |
Console.WriteLine($"SUCCESS: Process exited with code of {process.ExitCode}"); | |
} | |
else if (ignoreError) | |
{ | |
Console.WriteLine($"WARN: Process exited with code of {process.ExitCode}"); | |
} | |
else | |
{ | |
Console.WriteLine($"ERROR: Process exited with code of {process.ExitCode}"); | |
throw new Exception($"Process exited with non-zero exit code of {process.ExitCode}"); | |
} | |
} | |
finally | |
{ | |
process.Close(); | |
} | |
} | |
private void WriteConsoleOutput(string type, DataReceivedEventArgs eventArgs) | |
{ | |
if (eventArgs.Data != null) | |
{ | |
Console.WriteLine($"{type} : {eventArgs.Data}"); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Start-SshAgent | |
$startLocation = Get-Location | |
$RunDirectory = "F:\GIT\MyRepo" #Path to Repo | |
$UpstreamName = "Upstream" #Remote Name for Origin | |
$ForkName = "BlythMeister" #Remote Name for Fork | |
$BranchName = 'develop' #Branch in BOTH repos to sync | |
Set-Location $RunDirectory | |
write-host | |
write-host "Get Status" | |
&"C:\Program Files\Git\bin\git.exe" status | |
$continue = Read-Host 'Are You Sure You Want To Start? (y or n)' | |
if($continue.toLower() -ne "y") | |
{ | |
write-host "Stopping Process" | |
break | |
} | |
write-host | |
write-host "Fetch All" | |
&"C:\Program Files\Git\bin\git.exe" fetch --all | |
write-host | |
write-host "Checkout: _$ForkName/$BranchName" | |
&"C:\Program Files\Git\bin\git.exe" checkout "_$ForkName/$BranchName" | |
write-host | |
write-host "Merge To Head: _$ForkName/$BranchName" | |
&"C:\Program Files\Git\bin\git.exe" merge "_$ForkName/$BranchName" | |
write-host | |
write-host "Merge Previous Version: $UpstreamName/$BranchName" | |
&"C:\Program Files\Git\bin\git.exe" merge remotes/$UpstreamName/$BranchName | |
write-host | |
write-host "Get Status" | |
&"C:\Program Files\Git\bin\git.exe" status | |
$continue = Read-Host 'Good To Push? (y or n)' | |
if($continue.toLower() -ne "y") | |
{ | |
write-host "Stopping Process" | |
break | |
} | |
write-host | |
write-host "Push to $ForkName" | |
$data = "refs/heads/_$ForkName/$BranchName :refs/heads/$BranchName".Replace(" ", "") | |
&"C:\Program Files\Git\bin\git.exe" push --recurse-submodules=check --progress $ForkName $data | |
Set-Location $startLocation |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment