Exemplo n.º 1
0
        public static async Task RunAsync(
            OpenPrMessage openPrMessage,
            Installation installation,
            IInstallationTokenProvider installationTokenProvider,
            IPullRequest pullRequest,
            ILogger logger,
            ExecutionContext context)
        {
            if (installation == null)
            {
                logger.LogError("No installation found for {InstallationId}", openPrMessage.InstallationId);
                throw new Exception($"No installation found for InstallationId: {openPrMessage.InstallationId}");
            }

            var installationToken = await installationTokenProvider.GenerateAsync(
                new InstallationTokenParameters
            {
                AccessTokensUrl = string.Format(KnownGitHubs.AccessTokensUrlFormat, installation.InstallationId),
                AppId           = KnownGitHubs.AppId,
            },
                File.OpenText(Path.Combine(context.FunctionDirectory, $"../{KnownGitHubs.AppPrivateKey}")));

            logger.LogInformation("OpenPrFunction: Opening pull request for {Owner}/{RepoName}", installation.Owner, installation.RepoName);
            var id = await pullRequest.OpenAsync(new GitHubClientParameters
            {
                Password  = installationToken.Token,
                RepoName  = installation.RepoName,
                RepoOwner = installation.Owner,
            });

            if (id > 0)
            {
                logger.LogInformation("OpenPrFunction: Successfully opened pull request (#{PullRequestId}) for {Owner}/{RepoName}", id, installation.Owner, installation.RepoName);
            }
        }
        public static async Task RunAsync(
            IInstallationTokenProvider installationTokenProvider,
            CompressImagesMessage compressImagesMessage,
            ICollector <OpenPrMessage> openPrMessages,
            IRepoChecks repoChecks,
            ILogger logger,
            ExecutionContext context)
        {
            logger.LogInformation("CompressImagesFunction: starting run for {Owner}/{RepoName}", compressImagesMessage.Owner, compressImagesMessage.RepoName);
            var installationTokenParameters = new InstallationTokenParameters
            {
                AccessTokensUrl = string.Format(KnownGitHubs.AccessTokensUrlFormat, compressImagesMessage.InstallationId),
                AppId           = KnownGitHubs.AppId,
            };

            var installationToken = await installationTokenProvider.GenerateAsync(
                installationTokenParameters,
                File.OpenText(Path.Combine(context.FunctionDirectory, $"../{KnownGitHubs.AppPrivateKey}")));

            // check if repo is archived before starting work
            var isArchived = await repoChecks.IsArchived(new GitHubClientParameters
            {
                Password  = installationToken.Token,
                RepoName  = compressImagesMessage.RepoName,
                RepoOwner = compressImagesMessage.Owner
            });

            if (isArchived)
            {
                logger.LogInformation("CompressImagesFunction: skipping archived repo {Owner}/{RepoName}", compressImagesMessage.Owner, compressImagesMessage.RepoName);
                return;
            }

            var compressImagesParameters = new CompressimagesParameters
            {
                CloneUrl              = compressImagesMessage.CloneUrl,
                LocalPath             = LocalPath.CloneDir(Environment.GetEnvironmentVariable("TMP") ?? "/private/tmp/", compressImagesMessage.RepoName),
                Password              = installationToken.Token,
                RepoName              = compressImagesMessage.RepoName,
                RepoOwner             = compressImagesMessage.Owner,
                PgpPrivateKeyStream   = File.OpenRead(Path.Combine(context.FunctionDirectory, $"../{KnownGitHubs.PGPPrivateKeyFilename}")),
                PgPPassword           = File.ReadAllText(Path.Combine(context.FunctionDirectory, $"../{KnownGitHubs.PGPPasswordFilename}")),
                CompressImagesMessage = compressImagesMessage,
            };

            var didCompress = await CompressImages.RunAsync(compressImagesParameters, logger);

            if (didCompress)
            {
                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,
                });
            }

            logger.LogInformation("CompressImagesFunction: finished run for {Owner}/{RepoName}", compressImagesMessage.Owner, compressImagesMessage.RepoName);
        }
Exemplo n.º 3
0
        public static async Task RunAsync(
            OpenPrMessage openPrMessage,
            Installation installation,
            ICollector <Pr> prs,
            CloudTable settingsTable,
            IInstallationTokenProvider installationTokenProvider,
            IPullRequest pullRequest,
            ILogger logger,
            ExecutionContext context)
        {
            if (installation == null)
            {
                logger.LogError("No installation found for {InstallationId}", openPrMessage.InstallationId);
                throw new Exception($"No installation found for InstallationId: {openPrMessage.InstallationId}");
            }

            var installationToken = await installationTokenProvider.GenerateAsync(
                new InstallationTokenParameters
            {
                AccessTokensUrl = string.Format(KnownGitHubs.AccessTokensUrlFormat, installation.InstallationId),
                AppId           = KnownGitHubs.AppId,
            },
                KnownEnvironmentVariables.APP_PRIVATE_KEY);

            logger.LogInformation("OpenPrFunction: Opening pull request for {Owner}/{RepoName}", installation.Owner, installation.RepoName);

            var settings = await SettingsHelper.GetSettings(settingsTable, installation.InstallationId, installation.RepoName);

            if (settings != null && !string.IsNullOrEmpty(settings.DefaultBranchOverride))
            {
                logger.LogInformation(
                    "OpenPrFunction: default branch override for {Owner}/{RepoName} is {DefaultBranchOverride}",
                    installation.Owner,
                    installation.RepoName,
                    settings.DefaultBranchOverride);
            }

            var result = await pullRequest.OpenAsync(
                new GitHubClientParameters
            {
                Password  = installationToken.Token,
                RepoName  = installation.RepoName,
                RepoOwner = installation.Owner,
            },
                openPrMessage.Update,
                settings);

            if (result?.Id > 0)
            {
                logger.LogInformation("OpenPrFunction: Successfully opened pull request (#{PullRequestId}) for {Owner}/{RepoName}", result.Id, installation.Owner, installation.RepoName);
                prs.Add(result);
            }
        }
Exemplo n.º 4
0
        public static async Task RunAsync(
            CloudTable marketplaceTable,
            IInstallationTokenProvider installationTokenProvider,
            ILogger logger,
            ExecutionContext context)
        {
            logger.LogInformation("MarketplaceSync starting");
            var jwt = installationTokenProvider.GenerateJWT(
                new InstallationTokenParameters
            {
                AppId = KnownGitHubs.AppId,
            },
                KnownEnvironmentVariables.APP_PRIVATE_KEY);
            var currentPlans = KnownGitHubs.Plans.Keys.Where(k => KnownGitHubs.Plans[k] == -1 || KnownGitHubs.Plans[k] >= KnownGitHubs.SmallestLimitPaidPlan);

            foreach (var planId in currentPlans)
            {
                var planRequest = new HttpRequestMessage(HttpMethod.Get, $"https://api.github.com/marketplace_listing/plans/{planId}/accounts?per_page=100");
                planRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", jwt);
                planRequest.Headers.Add("User-Agent", "ImgBot");
                planRequest.Headers.Add("Accept", "application/vnd.github.machine-man-preview+json");

                var planResponse = await HttpClient.SendAsync(planRequest);

                var planJson = await planResponse.Content.ReadAsStringAsync();

                Account[] accountsInPlan = new Account[0];
                try
                {
                    accountsInPlan = JsonConvert.DeserializeObject <Account[]>(planJson);
                }
                catch (Exception)
                {
                    logger.LogInformation("SerializationError:> " + planJson);
                }

                logger.LogInformation("MarketplaceSync found {NumPlans} for {PlanId}", accountsInPlan.Length, planId);

                foreach (var account in accountsInPlan)
                {
                    var row = new Common.TableModels.Marketplace(account.id, account.login)
                    {
                        AccountType = account.type,
                        PlanId      = account.marketplace_purchase.plan.id
                    };
                    await marketplaceTable.ExecuteAsync(TableOperation.InsertOrMerge(row));
                }
            }

            logger.LogInformation("MarketplaceSync finished");
        }
Exemplo n.º 5
0
        public static async Task RunAsync(
            CloudTable marketplaceTable,
            IInstallationTokenProvider installationTokenProvider,
            ILogger logger,
            ExecutionContext context)
        {
            logger.LogInformation("MarketplaceSync starting");
            var jwt = installationTokenProvider.GenerateJWT(
                new InstallationTokenParameters
            {
                AppId = KnownGitHubs.AppId,
            },
                File.OpenText(Path.Combine(context.FunctionDirectory, $"../{KnownGitHubs.AppPrivateKey}")));

            foreach (var planId in new[] { 1749, 1750 })
            {
                var planRequest = new HttpRequestMessage(HttpMethod.Get, $"https://api.github.com/marketplace_listing/plans/{planId}/accounts");
                planRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", jwt);
                planRequest.Headers.Add("User-Agent", "ImgBot");
                planRequest.Headers.Add("Accept", "application/vnd.github.machine-man-preview+json");

                var planResponse = await HttpClient.SendAsync(planRequest);

                var planJson = await planResponse.Content.ReadAsStringAsync();

                Account[] accountsInPlan = new Account[0];
                try
                {
                    accountsInPlan = JsonConvert.DeserializeObject <Account[]>(planJson);
                }
                catch (Exception)
                {
                    logger.LogInformation("SerializationError:> " + planJson);
                }

                logger.LogInformation("MarketplaceSync found {NumPlans} for {PlanId}", accountsInPlan.Length, planId);

                foreach (var account in accountsInPlan)
                {
                    var row = new Common.TableModels.Marketplace(account.id, account.login)
                    {
                        AccountType = account.type,
                        PlanId      = account.marketplace_purchase.plan.id
                    };
                    await marketplaceTable.ExecuteAsync(TableOperation.InsertOrMerge(row));
                }
            }

            logger.LogInformation("MarketplaceSync finished");
        }
Exemplo n.º 6
0
        public static async Task RunAsync(
            DeleteBranchMessage deleteBranchMessage,
            Installation installation,
            IInstallationTokenProvider installationTokenProvider,
            ILogger logger,
            ExecutionContext context)
        {
            if (installation == null)
            {
                logger.LogError("No installation found for {InstallationId}", deleteBranchMessage.InstallationId);
                throw new Exception($"No installation found for InstallationId: {deleteBranchMessage.InstallationId}");
            }

            var installationToken = await installationTokenProvider.GenerateAsync(
                new InstallationTokenParameters
            {
                AccessTokensUrl = string.Format(KnownGitHubs.AccessTokensUrlFormat, installation.InstallationId),
                AppId           = KnownGitHubs.AppId,
            },
                KnownEnvironmentVariables.APP_PRIVATE_KEY);

            logger.LogInformation("DeleteBranchFunction: Deleting imgbot branch for {Owner}/{RepoName}", installation.Owner, installation.RepoName);

            var inMemoryCredentialStore = new InMemoryCredentialStore(new Octokit.Credentials(KnownGitHubs.Username, installationToken.Token));
            var githubClient            = new Octokit.GitHubClient(new Octokit.ProductHeaderValue("ImgBot"), inMemoryCredentialStore);

            var imgbotRefName = $"heads/{KnownGitHubs.BranchName}";

            Octokit.Reference imgbotBranchRef = null;
            try
            {
                imgbotBranchRef = await githubClient.Git.Reference.Get(installation.Owner, installation.RepoName, imgbotRefName);
            }
            catch
            {
            }

            if (imgbotBranchRef == null)
            {
                logger.LogInformation("DeleteBranchFunction: No imgbot branch found for {Owner}/{RepoName}", installation.Owner, installation.RepoName);
                return;
            }

            await githubClient.Git.Reference.Delete(installation.Owner, installation.RepoName, imgbotRefName);

            logger.LogInformation("DeleteBranchFunction: Successfully deleted imgbot branch for {Owner}/{RepoName}", installation.Owner, installation.RepoName);
        }
Exemplo n.º 7
0
        public static async Task RunAsync(
            IInstallationTokenProvider installationTokenProvider,
            CompressImagesMessage compressImagesMessage,
            ICollector <OpenPrMessage> openPrMessages,
            IRepoChecks repoChecks,
            ILogger logger,
            ExecutionContext context)
        {
            logger.LogInformation("CompressImagesFunction: starting run for {Owner}/{RepoName}", compressImagesMessage.Owner, compressImagesMessage.RepoName);
            var installationTokenParameters = new InstallationTokenParameters
            {
                AccessTokensUrl = string.Format(KnownGitHubs.AccessTokensUrlFormat, compressImagesMessage.InstallationId),
                AppId           = KnownGitHubs.AppId,
            };

            var installationToken = await installationTokenProvider.GenerateAsync(
                installationTokenParameters,
                KnownEnvironmentVariables.APP_PRIVATE_KEY);

            // check if repo is archived before starting work
            var isArchived = await repoChecks.IsArchived(new GitHubClientParameters
            {
                Password  = installationToken.Token,
                RepoName  = compressImagesMessage.RepoName,
                RepoOwner = compressImagesMessage.Owner
            });

            if (isArchived)
            {
                logger.LogInformation("CompressImagesFunction: skipping archived repo {Owner}/{RepoName}", compressImagesMessage.Owner, compressImagesMessage.RepoName);
                return;
            }

            // check if imgbot branch already exists before starting work
            var branchExists = await repoChecks.BranchExists(new GitHubClientParameters
            {
                Password  = installationToken.Token,
                RepoName  = compressImagesMessage.RepoName,
                RepoOwner = compressImagesMessage.Owner,
            });

            if (branchExists)
            {
                logger.LogInformation("CompressImagesFunction: skipping repo {Owner}/{RepoName} as branch exists", compressImagesMessage.Owner, compressImagesMessage.RepoName);
                return;
            }

            var compressImagesParameters = new CompressimagesParameters
            {
                CloneUrl              = compressImagesMessage.CloneUrl,
                LocalPath             = LocalPath.CloneDir(KnownEnvironmentVariables.TMP ?? "/private/tmp/", compressImagesMessage.RepoName),
                Password              = installationToken.Token,
                RepoName              = compressImagesMessage.RepoName,
                RepoOwner             = compressImagesMessage.Owner,
                PgpPrivateKey         = KnownEnvironmentVariables.PGP_PRIVATE_KEY,
                PgPPassword           = KnownEnvironmentVariables.PGP_PASSWORD,
                CompressImagesMessage = compressImagesMessage,
            };

            var didCompress = CompressImages.Run(compressImagesParameters, logger);

            if (didCompress)
            {
                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,
                });
            }

            logger.LogInformation("CompressImagesFunction: finished run for {Owner}/{RepoName}", compressImagesMessage.Owner, compressImagesMessage.RepoName);
        }
Exemplo n.º 8
0
        public static async Task RunAsync(
            IInstallationTokenProvider installationTokenProvider,
            CloudTable installationTable,
            CloudQueue openPrQueue,
            CloudQueue openPrPoisonQueue,
            ILogger logger,
            ExecutionContext context)
        {
            for (var i = 0; i < 100; i++)
            {
                System.Threading.Thread.Sleep(1000);

                var topQueueMessage = await openPrPoisonQueue.GetMessageAsync();

                if (topQueueMessage == null)
                {
                    continue;
                }

                // pre-emptively delete the message from the queue we are pulling from
                await openPrPoisonQueue.DeleteMessageAsync(topQueueMessage);

                var topMessage = JsonConvert.DeserializeObject <OpenPrMessage>(topQueueMessage.AsString);

                try
                {
                    var installation = (Installation)(await installationTable.ExecuteAsync(
                                                          TableOperation.Retrieve <Installation>(topMessage.InstallationId.ToString(), topMessage.RepoName)))
                                       .Result;

                    if (installation == null)
                    {
                        logger.LogInformation("Not listed in installation table");
                        continue;
                    }

                    logger.LogInformation($"https://github.com/{installation.Owner}/{installation.RepoName}");

                    var installationTokenParameters = new InstallationTokenParameters
                    {
                        AccessTokensUrl = string.Format(KnownGitHubs.AccessTokensUrlFormat, topMessage.InstallationId),
                        AppId           = KnownGitHubs.AppId,
                    };

                    var installationToken = await installationTokenProvider.GenerateAsync(
                        installationTokenParameters,
                        File.OpenText(Path.Combine(context.FunctionDirectory, $"../{KnownGitHubs.AppPrivateKey}")));

                    var appClient = new Octokit.GitHubClient(new Octokit.ProductHeaderValue("MyApp"))
                    {
                        Credentials = new Octokit.Credentials(installationToken.Token, Octokit.AuthenticationType.Bearer)
                    };

                    var limits = await appClient.Miscellaneous.GetRateLimits();

                    logger.LogInformation("Ratelimits:\n");
                    logger.LogInformation(JsonConvert.SerializeObject(limits));

                    // check if an 'imgbot' branch is open
                    var branches = await appClient.Repository.Branch.GetAll(installation.Owner, installation.RepoName);

                    var imgbotBranches = branches.Where(x => x.Name == "imgbot");

                    if (imgbotBranches.Count() == 0)
                    {
                        // we have no open imgbot branches right now, let's just leave
                        continue;
                    }
                    else
                    {
                        logger.LogInformation("Open 'imgbot' branch found");
                    }

                    // check for ImgBot PRs
                    var prs = await appClient.Repository.PullRequest.GetAllForRepository(installation.Owner, installation.RepoName);

                    var imgbotPrs = prs.Where(x => x.Head.Ref == "imgbot");

                    if (imgbotPrs.Count() > 0)
                    {
                        // we have an open imgbot PR right now, let's just leave
                        continue;
                    }
                    else
                    {
                        logger.LogInformation("Open 'imgbot' PR not found, do we need to open one?");
                    }

                    // query for closed ImgBot PRs
                    var searchRequest = new Octokit.SearchIssuesRequest("imgbot")
                    {
                        Type  = Octokit.IssueTypeQualifier.PullRequest,
                        Repos = new Octokit.RepositoryCollection {
                            installation.Owner + "/" + installation.RepoName
                        }
                    };

                    var imgbotIssues = await appClient.Search.SearchIssues(searchRequest);

                    if (imgbotIssues.TotalCount == 0)
                    {
                        // no imgbot prs in history, let's queue a message to get the pr open
                        await openPrQueue.AddMessageAsync(new CloudQueueMessage(JsonConvert.SerializeObject(topMessage)));
                    }
                    else
                    {
                        // this is the case where an 'imgbot' branch exists, but there are closed imgbot prs
                        var latestClosedPr  = imgbotIssues.Items.OrderByDescending(x => x.ClosedAt).First();
                        var potentialBranch = branches.First(x => x.Name == "imgbot");

                        var commitInImgbotBranch = await appClient.Repository.Commit
                                                   .Get(installation.Owner, installation.RepoName, potentialBranch.Commit.Sha);

                        if (commitInImgbotBranch.Commit.Author.Date > latestClosedPr.ClosedAt)
                        {
                            // if the branch is newer than the last closed imgbot PR then we should queue a message to get the pr open
                            await openPrQueue.AddMessageAsync(new CloudQueueMessage(JsonConvert.SerializeObject(topMessage)));
                        }
                    }
                }
                catch (Exception e)
                {
                    logger.LogError(e, "ERROR!");

                    // add it back to the poison queue
                    await openPrPoisonQueue.AddMessageAsync(topQueueMessage);
                }
            }
        }
Exemplo n.º 9
0
        public static async Task RunAsync(
            IInstallationTokenProvider installationTokenProvider,
            CompressImagesMessage compressImagesMessage,
            ICollector<OpenPrMessage> openPrMessages,
            ICollector<CompressImagesMessage> compressImagesMessages,
            CloudTable settingsTable,
            IRepoChecks repoChecks,
            ILogger logger,
            ExecutionContext context)
        {
            logger.LogInformation("CompressImagesFunction: starting run for {Owner}/{RepoName}", compressImagesMessage.Owner, compressImagesMessage.RepoName);
            var installationTokenParameters = new InstallationTokenParameters
            {
                AccessTokensUrl = string.Format(KnownGitHubs.AccessTokensUrlFormat, compressImagesMessage.InstallationId),
                AppId = KnownGitHubs.AppId,
            };
            var installationToken = await installationTokenProvider.GenerateAsync(
                installationTokenParameters,
                KnownEnvironmentVariables.APP_PRIVATE_KEY);

            // check if repo is archived before starting work
            var isArchived = await repoChecks.IsArchived(new GitHubClientParameters
            {
                Password = installationToken.Token,
                RepoName = compressImagesMessage.RepoName,
                RepoOwner = compressImagesMessage.Owner
            });

            if (isArchived)
            {
                logger.LogInformation("CompressImagesFunction: skipping archived repo {Owner}/{RepoName}", compressImagesMessage.Owner, compressImagesMessage.RepoName);
                return;
            }

            // check if imgbot branch already exists before starting work
            var branchExists = await repoChecks.BranchExists(new GitHubClientParameters
            {
                Password = installationToken.Token,
                RepoName = compressImagesMessage.RepoName,
                RepoOwner = compressImagesMessage.Owner,
            });

            if (branchExists && !compressImagesMessage.IsRebase)
            {
                logger.LogInformation("CompressImagesFunction: skipping repo {Owner}/{RepoName} as branch exists", compressImagesMessage.Owner, compressImagesMessage.RepoName);
                return;
            }

            var compressImagesParameters = new CompressimagesParameters
            {
                CloneUrl = compressImagesMessage.CloneUrl,
                LocalPath = LocalPath.CloneDir(KnownEnvironmentVariables.TMP ?? "/private/tmp/", compressImagesMessage.RepoName),
                Password = installationToken.Token,
                RepoName = compressImagesMessage.RepoName,
                RepoOwner = compressImagesMessage.Owner,
                IsRebase = compressImagesMessage.IsRebase,
                PgpPrivateKey = KnownEnvironmentVariables.PGP_PRIVATE_KEY,
                PgPPassword = KnownEnvironmentVariables.PGP_PASSWORD,
                CompressImagesMessage = compressImagesMessage,
                Settings = await Common.TableModels.SettingsHelper.GetSettings(settingsTable, compressImagesMessage.InstallationId, compressImagesMessage.RepoName),
            };

            var didCompress = CompressImages.Run(compressImagesParameters, compressImagesMessages, logger);

            if (didCompress && compressImagesParameters.CloneUrl.Contains(".wiki.git"))
            {
                logger.LogInformation("CompressImagesFunction: Successfully compressed images for {Owner}/{RepoName}/wiki", compressImagesMessage.Owner, compressImagesMessage.RepoName);
            }
            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,
                });
            }

            try
            {
                Directory.Delete(compressImagesParameters.LocalPath, recursive: true);
            }
            catch (Exception exception)
            {
                logger.LogError(exception, "Error cleaning up local directory");
            }

            logger.LogInformation("CompressImagesFunction: finished run for {Owner}/{RepoName}", compressImagesMessage.Owner, compressImagesMessage.RepoName);
        }