Skip to content

Commit

Permalink
Tool: Bring back mergefreeze API integration (#6905)
Browse files Browse the repository at this point in the history
* Tool: Bring back mergefreeze API integration

Context: #5628 (comment)

Unfortunately, the API doesn't work.

* Lay out how this would work in the database - but instead, do it ephemerally for now

* Remove model

* Maintain state (the easy way for now)
  • Loading branch information
mikermcneil authored Jul 27, 2022
1 parent 8369f6b commit 39fea29
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 63 deletions.
84 changes: 77 additions & 7 deletions website/api/controllers/webhooks/receive-from-github.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,13 @@ module.exports = {

let GitHub = require('machinepack-github');

let IS_FROZEN = false;// « Set this to `true` whenever a freeze is in effect, then set it back to `false` when the freeze ends.
// Is this in use?
// > For context on the history of this bit of code, which has gone been
// > implemented a couple of different ways, and gone back and forth, check out:
// > https://github.com/fleetdm/fleet/pull/5628#issuecomment-1196175485
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// let IS_FROZEN = false;// « Set this to `true` whenever a freeze is in effect, then set it back to `false` when the freeze ends.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

let GITHUB_USERNAMES_OF_BOTS_AND_MAINTAINERS = [// « Used in multiple places below.
'sailsbot',
Expand Down Expand Up @@ -71,6 +77,10 @@ module.exports = {

let GITHUB_USERNAME_OF_DRI_FOR_LABELS = 'noahtalerman';// « Used below (FUTURE: Remove this capability as Fleet has outgrown it. 2022-05-05)

if (!sails.config.custom.mergeFreezeAccessToken) {
throw new Error('An access token for the MergeFreeze API (sails.config.custom.mergeFreezeAccessToken) is required to enable automated unfreezing/freezing of changes based on the files they change. Please ask for help in #g-digital-experience, whether you are testing locally or using this as a live webhook.');
}

if (!sails.config.custom.slackWebhookUrlForGithubBot) {
throw new Error('No Slack webhook URL configured for the GitHub bot to notify with alerts! (Please set `sails.config.custom.slackWebhookUrlForGithubBot`.)');
}//•
Expand Down Expand Up @@ -218,18 +228,78 @@ module.exports = {
isGithubUserMaintainerOrDoesntMatter: GITHUB_USERNAMES_OF_BOTS_AND_MAINTAINERS.includes(sender.login.toLowerCase())
});

// Check whether the "main" branch is currently frozen (i.e. a feature freeze)
// [?] https://docs.mergefreeze.com/web-api#get-freeze-status
let isMainBranchFrozen = (await sails.helpers.http.get('https://www.mergefreeze.com/api/branches/fleetdm/fleet/main', { access_token: sails.config.custom.mergeFreezeAccessToken })).frozen;//eslint-disable-line camelcase

// Now, if appropriate, auto-approve the change.
if (isAutoApproved) {
// [?] https://docs.github.com/en/rest/reference/pulls#create-a-review-for-a-pull-request
await sails.helpers.http.post(`https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}/reviews`, {
event: 'APPROVE'
}, baseHeaders);
} else if (IS_FROZEN) {
// [?] https://docs.github.com/en/rest/reference/pulls#create-a-review-for-a-pull-request
await sails.helpers.http.post(`https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}/reviews`, {
event: 'REQUEST_CHANGES',
body: 'The repository is currently frozen for an upcoming release. \n> After the freeze has ended, please dismiss this review. \n\nIn case of emergency, you can dismiss this review and merge now.'
}, baseHeaders);

// Since we're only using a single instance, and because the worst case scenario is that we refreeze some
// all-markdown PRs that had already been frozen, instead of using the database, we'll just use a little
// in-memory pocket here of PRs seen by this instance of the Sails app. To get around any issues with this,
// users can edit and resave the PR description to trigger their PR to be unfrozen.
// FUTURE: Go through the trouble to migrate the database and make a little Platform model to hold this state in.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Grab the set of GitHub pull request numbers the bot considers "unfrozen".
sails.pocketOfPrNumbersUnfrozen = sails.pocketOfPrNumbersUnfrozen || [];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// If "main" is explicitly frozen, then unfreeze this PR because it no longer contains
// (or maybe never did contain) changes to freezeworthy files.
if (isMainBranchFrozen) {

sails.pocketOfPrNumbersUnfrozen = _.union(sails.pocketOfPrNumbersUnfrozen, [ prNumber ]);

// [?] See May 6th, 2022 changelog, which includes this code sample:
// (https://www.mergefreeze.com/news)
// (but as of July 26, 2022, I didn't see it documented here: https://docs.mergefreeze.com/web-api#post-freeze-status)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// > You may now freeze or unfreeze a single PR (while maintaining the overall freeze) via the Web API.
// ```
// curl -d "frozen=true&user_name=Scooby Doo&unblocked_prs=[3]" -X POST https://www.mergefreeze.com/api/branches/mergefreeze/core/master/?access_token=[Your access token]
// ```
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
await sails.helpers.http.post(`https://www.mergefreeze.com/api/branches/fleetdm/fleet/main?access_token=${encodeURIComponent(sails.config.custom.mergeFreezeAccessToken)}`, {
frozen: true,
user_name: 'fleet-release',//eslint-disable-line camelcase
unblocked_prs: sails.pocketOfPrNumbersUnfrozen,//eslint-disable-line camelcase
});

}//fi

} else {
// If "main" is explicitly frozen, then freeze this PR because it now contains
// (or maybe always did contain) changes to freezeworthy files.
if (isMainBranchFrozen) {

sails.pocketOfPrNumbersUnfrozen = _.difference(sails.pocketOfPrNumbersUnfrozen, [ prNumber ]);

// [?] See explanation above.
await sails.helpers.http.post(`https://www.mergefreeze.com/api/branches/fleetdm/fleet/main?access_token=${encodeURIComponent(sails.config.custom.mergeFreezeAccessToken)}`, {
frozen: true,
user_name: 'fleet-release',//eslint-disable-line camelcase
unblocked_prs: sails.pocketOfPrNumbersUnfrozen,//eslint-disable-line camelcase
});
}//fi

// Is this in use?
// > For context on the history of this bit of code, which has gone been
// > implemented a couple of different ways, and gone back and forth, check out:
// > https://github.com/fleetdm/fleet/pull/5628#issuecomment-1196175485
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// if (IS_FROZEN) {
// // [?] https://docs.github.com/en/rest/reference/pulls#create-a-review-for-a-pull-request
// await sails.helpers.http.post(`https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}/reviews`, {
// event: 'REQUEST_CHANGES',
// body: 'The repository is currently frozen for an upcoming release. \n> After the freeze has ended, please dismiss this review. \n\nIn case of emergency, you can dismiss this review and merge now.'
// }, baseHeaders);
// }//fi
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
}

}
Expand Down
5 changes: 4 additions & 1 deletion website/assets/.eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@
// Make sure backend globals aren't indadvertently tolerated in our client-side JS:
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
"sails": false,
"User": false
"User": false,
"HistoricalUsageSnapshot": false,
"Quote": false,
"Subscription": false,
// ...and any other backend globals (e.g. `"Organization": false`)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
}
Expand Down
116 changes: 61 additions & 55 deletions website/scripts/freeze-open-pull-requests.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
module.exports = {


friendlyName: 'Freeze open pull requests',


Expand All @@ -22,62 +21,69 @@ module.exports = {
},


fn: async function ({dry: isDryRun, limit: maxNumPullRequestsToCheck }) {

sails.log('Running custom shell script... (`sails run freeze-open-pull-requests`)');

let owner = 'fleetdm';
let repo = 'fleet';
let baseHeaders = {
'User-Agent': 'sails run freeze-open-pull-requests',
'Authorization': `token ${sails.config.custom.githubAccessToken}`
};

// Fetch open pull requests
// [?] https://docs.github.com/en/rest/pulls/pulls#list-pull-requests
let openPullRequests = await sails.helpers.http.get(`https://api.github.com/repos/${owner}/${repo}/pulls`, {
state: 'open',
per_page: maxNumPullRequestsToCheck,//eslint-disable-line camelcase
}, baseHeaders);

if (openPullRequests.length > maxNumPullRequestsToCheck) {
openPullRequests = openPullRequests.slice(0,maxNumPullRequestsToCheck);
}

let SECONDS_TO_WAIT = 5;
sails.log(`Examining and potentially freezing ${openPullRequests.length} PRs very soon… (To cancel, press CTRL+C quickly within ${SECONDS_TO_WAIT}s!)`);
await sails.helpers.flow.pause(SECONDS_TO_WAIT*1000);

// For all open pull requests…
await sails.helpers.flow.simultaneouslyForEach(openPullRequests, async(pullRequest)=>{

let prNumber = pullRequest.number;
let prAuthor = pullRequest.user.login;
require('assert')(prAuthor !== undefined);

// Freeze, if appropriate.
// (Check versus the intersection of DRIs for all changed files to make sure SOMEONE is preapproved for all of them.)
let isAuthorPreapproved = await sails.helpers.githubAutomations.getIsPrPreapproved.with({
prNumber: prNumber,
isGithubUserMaintainerOrDoesntMatter: true// « doesn't matter here because no auto-approval is happening. Worst case, a community PR to an area with a "*" in the DRI mapping remains unfrozen.
});

if (isDryRun) {
sails.log(`#${prNumber} by @${prAuthor}:`, isAuthorPreapproved ? 'Would have skipped freeze…' : 'Would have frozen…');
} else {
sails.log(`#${prNumber} by @${prAuthor}:`, isAuthorPreapproved ? 'Skipping freeze…' : 'Freezing…');
if (!isAuthorPreapproved) {
// [?] https://docs.github.com/en/rest/reference/pulls#create-a-review-for-a-pull-request
await sails.helpers.http.post(`https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}/reviews`, {
event: 'REQUEST_CHANGES',
body: 'The repository has been frozen for an upcoming release. In case of emergency, you can dismiss this review and merge.'
}, baseHeaders);
}//fi
}
});

fn: async function () {
// Is this in use?
// > For context on the history of this bit of code, which has gone been
// > implemented a couple of different ways, and gone back and forth, check out:
// > https://github.com/fleetdm/fleet/pull/5628#issuecomment-1196175485
throw new Error('Not currently in use. See comments in this script for more information.');
}

// fn: async function ({dry: isDryRun, limit: maxNumPullRequestsToCheck }) {

// sails.log('Running custom shell script... (`sails run freeze-open-pull-requests`)');

// let owner = 'fleetdm';
// let repo = 'fleet';
// let baseHeaders = {
// 'User-Agent': 'sails run freeze-open-pull-requests',
// 'Authorization': `token ${sails.config.custom.githubAccessToken}`
// };

// // Fetch open pull requests
// // [?] https://docs.github.com/en/rest/pulls/pulls#list-pull-requests
// let openPullRequests = await sails.helpers.http.get(`https://api.github.com/repos/${owner}/${repo}/pulls`, {
// state: 'open',
// per_page: maxNumPullRequestsToCheck,//eslint-disable-line camelcase
// }, baseHeaders);

// if (openPullRequests.length > maxNumPullRequestsToCheck) {
// openPullRequests = openPullRequests.slice(0,maxNumPullRequestsToCheck);
// }

// let SECONDS_TO_WAIT = 5;
// sails.log(`Examining and potentially freezing ${openPullRequests.length} PRs very soon… (To cancel, press CTRL+C quickly within ${SECONDS_TO_WAIT}s!)`);
// await sails.helpers.flow.pause(SECONDS_TO_WAIT*1000);

// // For all open pull requests…
// await sails.helpers.flow.simultaneouslyForEach(openPullRequests, async(pullRequest)=>{

// let prNumber = pullRequest.number;
// let prAuthor = pullRequest.user.login;
// require('assert')(prAuthor !== undefined);

// // Freeze, if appropriate.
// // (Check versus the intersection of DRIs for all changed files to make sure SOMEONE is preapproved for all of them.)
// let isAuthorPreapproved = await sails.helpers.githubAutomations.getIsPrPreapproved.with({
// prNumber: prNumber,
// isGithubUserMaintainerOrDoesntMatter: true// « doesn't matter here because no auto-approval is happening. Worst case, a community PR to an area with a "*" in the DRI mapping remains unfrozen.
// });

// if (isDryRun) {
// sails.log(`#${prNumber} by @${prAuthor}:`, isAuthorPreapproved ? 'Would have skipped freeze…' : 'Would have frozen…');
// } else {
// sails.log(`#${prNumber} by @${prAuthor}:`, isAuthorPreapproved ? 'Skipping freeze…' : 'Freezing…');
// if (!isAuthorPreapproved) {
// // [?] https://docs.github.com/en/rest/reference/pulls#create-a-review-for-a-pull-request
// await sails.helpers.http.post(`https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}/reviews`, {
// event: 'REQUEST_CHANGES',
// body: 'The repository has been frozen for an upcoming release. In case of emergency, you can dismiss this review and merge.'
// }, baseHeaders);
// }//fi
// }
// });

// }

};

0 comments on commit 39fea29

Please sign in to comment.