Skip to content

Commit

Permalink
Implemented a user-triggered rebase feature
Browse files Browse the repository at this point in the history
Co-Authored-By: Sigrun Arna Sigurdardottir <sasig@kth.se>
Co-Authored-By: Javier Ron <javierron90@gmail.com>
  • Loading branch information
javierron and s1grun committed May 14, 2020
1 parent 4966216 commit 7900250
Show file tree
Hide file tree
Showing 17 changed files with 717 additions and 23 deletions.
2 changes: 2 additions & 0 deletions Common/Messages/CompressImagesMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ public class CompressImagesMessage
public string Owner { get; set; }

public int InstallationId { get; set; }

public bool IsRebase { get; set; }
}
}
2 changes: 2 additions & 0 deletions Common/Messages/OpenPrMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@ public class OpenPrMessage
public string RepoName { get; set; }

public string CloneUrl { get; set; }

public bool Update { get; set; }
}
}
2 changes: 2 additions & 0 deletions Common/Messages/RouterMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ public class RouterMessage
public string CloneUrl { get; set; }

public string Owner { get; set; }

public bool IsRebase { get; set; }
}
}
137 changes: 131 additions & 6 deletions CompressImagesFunction/CompressImages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ public static bool Run(CompressimagesParameters parameters, ICollector<CompressI
{
CredentialsProvider = credentialsProvider,
};

Repository.Clone(parameters.CloneUrl, parameters.LocalPath, cloneOptions);

var repo = new Repository(parameters.LocalPath);
Expand All @@ -53,7 +52,7 @@ public static bool Run(CompressimagesParameters parameters, ICollector<CompressI
return false;
}

if (repo.Network.ListReferences(remote, credentialsProvider).Any(x => x.CanonicalName == $"refs/heads/{KnownGitHubs.BranchName}"))
if (!parameters.IsRebase && repo.Network.ListReferences(remote, credentialsProvider).Any(x => x.CanonicalName == $"refs/heads/{KnownGitHubs.BranchName}"))
{
logger.LogInformation("CompressImagesFunction: branch already exists for {Owner}/{RepoName}", parameters.RepoOwner, parameters.RepoName);
return false;
Expand Down Expand Up @@ -123,8 +122,8 @@ public static bool Run(CompressimagesParameters parameters, ICollector<CompressI
return false;
}

// Should not create branch if we are compressing Wiki
if (isWikiCompress == false)
// Should not create branch if we are compressing Wiki or performing rebase
if (isWikiCompress == false && !parameters.IsRebase)
{
// check out the branch
repo.CreateBranch(KnownGitHubs.BranchName);
Expand All @@ -135,7 +134,53 @@ public static bool Run(CompressimagesParameters parameters, ICollector<CompressI
repo.Reset(ResetMode.Mixed, repo.Head.Tip);

// optimize images
var imagePaths = ImageQuery.FindImages(parameters.LocalPath, repoConfiguration);
string[] imagePaths;
List<string> addedOrModifiedImagePaths = new List<string>();
List<string> deletedImagePaths = new List<string>();
if (parameters.IsRebase)
{
var refspec = string.Format("{0}:{0}", KnownGitHubs.BranchName);
Commands.Fetch(repo, "origin", new List<string> { refspec }, null, "fetch");

var diff = repo.Diff.Compare<TreeChanges>(repo.Branches[KnownGitHubs.BranchName].Commits.ElementAt(1).Tree, repo.Head.Tip.Tree);

if (diff == null)
{
logger.LogInformation("Something went wrong while doing rebase");
return false;
}

foreach (TreeEntryChanges c in diff)
{
if (KnownImgPatterns.ImgExtensions.Contains(Path.GetExtension(c.Path)))
{
var path = Path.Combine(parameters.LocalPath, c.Path).Replace("\\", "/");
var oldpath = Path.Combine(parameters.LocalPath, c.OldPath).Replace("\\", "/");

switch (c.Status)
{
case ChangeKind.Added:
case ChangeKind.Modified:
addedOrModifiedImagePaths.Add(path);
break;
case ChangeKind.Renamed:
addedOrModifiedImagePaths.Add(path);
deletedImagePaths.Add(oldpath);
break;
case ChangeKind.Deleted:
deletedImagePaths.Add(path);
break;
}
}
}

imagePaths = ImageQuery.FilterOutIgnoredFiles(addedOrModifiedImagePaths, repoConfiguration);
}
else
{
imagePaths = ImageQuery.FindImages(parameters.LocalPath, repoConfiguration);
}

var optimizedImages = OptimizeImages(repo, parameters.LocalPath, imagePaths, logger, repoConfiguration.AggressiveCompression);
if (optimizedImages.Length == 0)
return false;
Expand All @@ -156,6 +201,81 @@ public static bool Run(CompressimagesParameters parameters, ICollector<CompressI
var signature = new Signature(KnownGitHubs.ImgBotLogin, KnownGitHubs.ImgBotEmail, DateTimeOffset.Now);
repo.Commit(commitMessage, signature, signature);

if (parameters.IsRebase)
{
var baseBranch = repo.Head;
var newCommit = baseBranch.Tip;
var oldCommit = repo.Branches[KnownGitHubs.BranchName].Tip;

// we need to reset the default branch so that we can
// rebase to it later.
repo.Reset(ResetMode.Hard, repo.Head.Commits.ElementAt(1));

// checkout to imgbot branch. TODO: remove because this is needed earlier on diff
Commands.Checkout(repo, KnownGitHubs.BranchName);

// cherry-pick
var cherryPickOptions = new CherryPickOptions()
{
MergeFileFavor = MergeFileFavor.Theirs,
};
var cherryPickResult = repo.CherryPick(newCommit, signature, cherryPickOptions);

if (cherryPickResult.Status == CherryPickStatus.Conflicts)
{
var status = repo.RetrieveStatus(new LibGit2Sharp.StatusOptions() { });
foreach (var item in status)
{
if (item.State == FileStatus.Conflicted)
{
Commands.Stage(repo, item.FilePath);
}
}

repo.Commit(commitMessage, signature, signature);
}

// New commit message creation
var previousCommitResults = CompressionResult.ParseCommitMessage(oldCommit.Message);
var mergedResults = CompressionResult.Merge(optimizedImages, previousCommitResults);
var filteredResults = CompressionResult.Filter(mergedResults, deletedImagePaths.ToArray());
var squashCommitMessage = CommitMessage.Create(filteredResults);

// squash
var baseCommit = repo.Head.Commits.ElementAt(2);
repo.Reset(ResetMode.Soft, baseCommit);
repo.Commit(squashCommitMessage, signature, signature);

// rebase
var rebaseOptions = new RebaseOptions()
{
FileConflictStrategy = CheckoutFileConflictStrategy.Theirs,
};

var rebaseResult = repo.Rebase.Start(repo.Head, baseBranch, null, new Identity(KnownGitHubs.ImgBotLogin, KnownGitHubs.ImgBotEmail), rebaseOptions);

while (rebaseResult.Status == RebaseStatus.Conflicts)
{
var status = repo.RetrieveStatus(new LibGit2Sharp.StatusOptions() { });
foreach (var item in status)
{
if (item.State == FileStatus.Conflicted)
{
if (imagePaths.Contains(Path.Combine(parameters.LocalPath, item.FilePath)))
{
Commands.Stage(repo, item.FilePath);
}
else
{
Commands.Remove(repo, item.FilePath);
}
}
}

rebaseResult = repo.Rebase.Continue(new Identity(KnownGitHubs.ImgBotLogin, KnownGitHubs.ImgBotEmail), rebaseOptions);
}
}

// We just made a normal commit, now we are going to capture all the values generated from that commit
// then rewind and make a signed commit
var commitBuffer = Commit.CreateBuffer(
Expand Down Expand Up @@ -217,7 +337,12 @@ public static bool Run(CompressimagesParameters parameters, ICollector<CompressI
}
else
{
repo.Network.Push(remote, $"refs/heads/{KnownGitHubs.BranchName}", new PushOptions
var refs = $"refs/heads/{KnownGitHubs.BranchName}";
if (parameters.IsRebase)
refs = refs.Insert(0, "+");
logger.LogInformation("refs: {refs}", refs);

repo.Network.Push(remote, refs, new PushOptions
{
CredentialsProvider = credentialsProvider,
});
Expand Down
6 changes: 4 additions & 2 deletions CompressImagesFunction/CompressImagesFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ public static async Task RunAsync(
AccessTokensUrl = string.Format(KnownGitHubs.AccessTokensUrlFormat, compressImagesMessage.InstallationId),
AppId = KnownGitHubs.AppId,
};

var installationToken = await installationTokenProvider.GenerateAsync(
installationTokenParameters,
KnownEnvironmentVariables.APP_PRIVATE_KEY);
Expand All @@ -103,7 +102,7 @@ public static async Task RunAsync(
RepoOwner = compressImagesMessage.Owner,
});

if (branchExists)
if (branchExists && !compressImagesMessage.IsRebase)
{
logger.LogInformation("CompressImagesFunction: skipping repo {Owner}/{RepoName} as branch exists", compressImagesMessage.Owner, compressImagesMessage.RepoName);
return;
Expand All @@ -116,6 +115,7 @@ public static async Task RunAsync(
Password = installationToken.Token,
RepoName = compressImagesMessage.RepoName,
RepoOwner = compressImagesMessage.Owner,
IsRebase = compressImagesMessage.IsRebase,
PgpPrivateKey = KnownEnvironmentVariables.PGP_PRIVATE_KEY,
PgPPassword = KnownEnvironmentVariables.PGP_PASSWORD,
CompressImagesMessage = compressImagesMessage,
Expand All @@ -130,12 +130,14 @@ public static async Task RunAsync(
}
else if (didCompress)
{
var update = compressImagesMessage.IsRebase;
logger.LogInformation("CompressImagesFunction: Successfully compressed images for {Owner}/{RepoName}", compressImagesMessage.Owner, compressImagesMessage.RepoName);
openPrMessages.Add(new OpenPrMessage
{
InstallationId = compressImagesMessage.InstallationId,
RepoName = compressImagesMessage.RepoName,
CloneUrl = compressImagesMessage.CloneUrl,
Update = compressImagesMessage.IsRebase,
});
}

Expand Down
2 changes: 2 additions & 0 deletions CompressImagesFunction/CompressimagesParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public class CompressimagesParameters

public string PgPPassword { get; set; }

public bool IsRebase { get; set; }

public Common.TableModels.Settings Settings { get; set; }

public CompressImagesMessage CompressImagesMessage { get; set; }
Expand Down
2 changes: 1 addition & 1 deletion CompressImagesFunction/CompressionResult.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace CompressImagesFunction
{
public class CompressionResult
public partial class CompressionResult
{
public string Title { get; set; }

Expand Down
70 changes: 70 additions & 0 deletions CompressImagesFunction/CompressionResultUtil.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;

namespace CompressImagesFunction
{
public partial class CompressionResult
{
public static CompressionResult[] ParseCommitMessage(string commitBody)
{
try
{
var compressionResults = new List<CompressionResult>();

var commitLines = commitBody.Split(new[] { '\r', '\n' });
for (var i = 0; i < commitLines.Length; i++)
{
if (i == 0 || string.IsNullOrWhiteSpace(commitLines[i]))
{
// skip the first line and blank lines
continue;
}

if (commitLines[i].StartsWith("Signed-off-by:") || commitLines[i].StartsWith("*Total --"))
{
// skip the DCO line
continue;
}

var pattern = @"\*?(.*) -- (.*)kb -> (.*)kb \((.*)%\)";
var capture = Regex.Matches(commitLines[i], pattern)[0];

compressionResults.Add(new CompressionResult
{
Title = capture.Groups[1].Value,
SizeBefore = Convert.ToDouble(capture.Groups[2].Value),
SizeAfter = Convert.ToDouble(capture.Groups[3].Value),
});
}

return compressionResults.ToArray();
}
catch
{
// commit messages can be out of our control
return null;
}
}

public static CompressionResult[] Merge(CompressionResult[] newOptimizedImages, CompressionResult[] previousCommitResults)
{
List<CompressionResult> list = new List<CompressionResult>();
list.AddRange(newOptimizedImages);
list.AddRange(previousCommitResults);

var nonRepeat = list.GroupBy(x => x.Title).Select(y => y.First());

return nonRepeat.ToArray();
}

public static CompressionResult[] Filter(CompressionResult[] optimizedImages, string[] toRemove)
{
var relativePaths = toRemove.Select(path => Path.GetFileName(path));
var filtered = optimizedImages.Where(r => !relativePaths.Contains(r.Title));
return filtered.ToArray();
}
}
}
9 changes: 7 additions & 2 deletions CompressImagesFunction/ImageQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,21 @@ public static string[] FindImages(string localPath, RepoConfiguration repoConfig
.Where(x => KnownImgPatterns.ImgExtensions.Contains(Path.GetExtension(x).ToLower()))
.Select(x => x.Replace("\\", "/"));

return FilterOutIgnoredFiles(images, repoConfiguration);
}

public static string[] FilterOutIgnoredFiles(IEnumerable<string> imagePaths, RepoConfiguration repoConfiguration)
{
if (repoConfiguration.IgnoredFiles != null)
{
foreach (var ignorePattern in repoConfiguration.IgnoredFiles)
{
var pattern = new Regex(NormalizePattern(ignorePattern), RegexOptions.IgnoreCase);
images = images.Where(x => !pattern.IsMatch(x));
imagePaths = imagePaths.Where(x => !pattern.IsMatch(x));
}
}

return images.ToArray();
return imagePaths.ToArray();
}

// this is to provide backwards compatibility with the previous globbing
Expand Down
2 changes: 1 addition & 1 deletion OpenPrFunction/IPullRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ namespace OpenPrFunction
{
public interface IPullRequest
{
Task<Pr> OpenAsync(GitHubClientParameters parameters, Settings settings = null);
Task<Pr> OpenAsync(GitHubClientParameters parameters, bool update, Settings settings = null);
}
}
1 change: 1 addition & 0 deletions OpenPrFunction/OpenPr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public static async Task RunAsync(
RepoName = installation.RepoName,
RepoOwner = installation.Owner,
},
openPrMessage.Update,
settings);

if (result?.Id > 0)
Expand Down
Loading

0 comments on commit 7900250

Please sign in to comment.