Website: Create Platform model and use platform record to track mergefreeze status. (#13681)

Closes: #11755

Changes:
- Created a new model: `Platform` that has a single attribute:
`currentUnfrozenGitHubPrNumbers`
- Updated bootstrap.js to throw an error if more than one platform
record exists, and to create a platform record when the server is lifted
with the `--drop` flag.
- Updated the receive-from-github webhook to use a Platform record to
track the PRs that are currently unfrozen in the fleetdm/fleet repo.

Before this Pr is merged, we will need to:
- [x] Migrate the Fleet website's database to add the new database
table.
- [x] Create a single platform record.
This commit is contained in:
Eric 2023-09-05 16:31:40 -05:00 committed by GitHub
parent 51485beb40
commit ac8150a319
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 64 additions and 16 deletions

2
website/.eslintrc vendored
View File

@ -48,7 +48,7 @@
"NewsletterSubscription": true, "NewsletterSubscription": true,
"VantaConnection": true, "VantaConnection": true,
"CertificateSigningRequest": true, "CertificateSigningRequest": true,
"Platform": true,
// …and any others. // …and any others.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
}, },

View File

@ -26,14 +26,17 @@ module.exports = {
fn: async function ({botSignature, action, sender, repository, changes, issue, comment, pull_request: pr, label, release}) { fn: async function ({botSignature, action, sender, repository, changes, issue, comment, pull_request: pr, label, release}) {
// Since we're only using a single instance, and because the worst case scenario is that we refreeze some // Grab the set of GitHub pull request numbers the bot considers "unfrozen" from the platform record.
// all-markdown PRs that had already been frozen, instead of using the database, we'll just use a little // If there is more than one platform record, or it is missing, we'll throw an error.
// in-memory pocket here of PRs seen by this instance of the Sails app. To get around any issues with this, let platformRecords = await Platform.find();
// users can edit and resave the PR description to trigger their PR to be unfrozen. let platformRecord = platformRecords[0];
// FUTURE: Go through the trouble to migrate the database and make a little Platform model to hold this state in. if(!platformRecord) {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - throw new Error(`Consistency violation: when the GitHub webhook received an event, no platform record was found.`);
// Grab the set of GitHub pull request numbers the bot considers "unfrozen". } else if(platformRecords.length > 1) {
sails.pocketOfPrNumbersUnfrozen = sails.pocketOfPrNumbersUnfrozen || []; throw new Error(`Consistency violation: when the GitHub webhook received an event, more than one platform record was found.`);
}
let pocketOfPrNumbersUnfrozen = platformRecord.currentUnfrozenGitHubPrNumbers;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -453,8 +456,8 @@ module.exports = {
// Note: We'll only do this if the PR is from the fleetdm/fleet repo. // Note: We'll only do this if the PR is from the fleetdm/fleet repo.
if (isMainBranchFrozen && repo === 'fleet') { if (isMainBranchFrozen && repo === 'fleet') {
sails.pocketOfPrNumbersUnfrozen = _.union(sails.pocketOfPrNumbersUnfrozen, [ prNumber ]); pocketOfPrNumbersUnfrozen = _.union(pocketOfPrNumbersUnfrozen, [ prNumber ]);
sails.log.verbose('#'+prNumber+' autoapproved, main branch is frozen... prNumbers unfrozen:',sails.pocketOfPrNumbersUnfrozen); sails.log.verbose('#'+prNumber+' autoapproved, main branch is frozen... prNumbers unfrozen:',pocketOfPrNumbersUnfrozen);
// [?] See May 6th, 2022 changelog, which includes this code sample: // [?] See May 6th, 2022 changelog, which includes this code sample:
// (https://www.mergefreeze.com/news) // (https://www.mergefreeze.com/news)
@ -467,9 +470,10 @@ module.exports = {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
await sails.helpers.http.post(`https://www.mergefreeze.com/api/branches/fleetdm/fleet/main?access_token=${encodeURIComponent(sails.config.custom.mergeFreezeAccessToken)}`, { await sails.helpers.http.post(`https://www.mergefreeze.com/api/branches/fleetdm/fleet/main?access_token=${encodeURIComponent(sails.config.custom.mergeFreezeAccessToken)}`, {
user_name: 'fleet-release',//eslint-disable-line camelcase user_name: 'fleet-release',//eslint-disable-line camelcase
unblocked_prs: sails.pocketOfPrNumbersUnfrozen,//eslint-disable-line camelcase unblocked_prs: pocketOfPrNumbersUnfrozen,//eslint-disable-line camelcase
}); });
// Update the Platform record to have the current unfrozen PR numbers
await Platform.updateOne({id: platformRecord.id}).set({currentUnfrozenGitHubPrNumbers: pocketOfPrNumbersUnfrozen});
}//fi }//fi
} else { } else {
@ -478,14 +482,16 @@ module.exports = {
// Note: We'll only do this if the PR is from the fleetdm/fleet repo. // Note: We'll only do this if the PR is from the fleetdm/fleet repo.
if (isMainBranchFrozen && repo === 'fleet') { if (isMainBranchFrozen && repo === 'fleet') {
sails.pocketOfPrNumbersUnfrozen = _.difference(sails.pocketOfPrNumbersUnfrozen, [ prNumber ]); pocketOfPrNumbersUnfrozen = _.difference(pocketOfPrNumbersUnfrozen, [ prNumber ]);
sails.log.verbose('#'+prNumber+' not autoapproved, main branch is frozen... prNumbers unfrozen:',sails.pocketOfPrNumbersUnfrozen); sails.log.verbose('#'+prNumber+' not autoapproved, main branch is frozen... prNumbers unfrozen:',pocketOfPrNumbersUnfrozen);
// [?] See explanation above. // [?] See explanation above.
await sails.helpers.http.post(`https://www.mergefreeze.com/api/branches/fleetdm/fleet/main?access_token=${encodeURIComponent(sails.config.custom.mergeFreezeAccessToken)}`, { await sails.helpers.http.post(`https://www.mergefreeze.com/api/branches/fleetdm/fleet/main?access_token=${encodeURIComponent(sails.config.custom.mergeFreezeAccessToken)}`, {
user_name: 'fleet-release',//eslint-disable-line camelcase user_name: 'fleet-release',//eslint-disable-line camelcase
unblocked_prs: sails.pocketOfPrNumbersUnfrozen,//eslint-disable-line camelcase unblocked_prs: pocketOfPrNumbersUnfrozen,//eslint-disable-line camelcase
}); });
// Update the Platform record to have the current unfrozen PR numbers
await Platform.updateOne({id: platformRecord.id}).set({currentUnfrozenGitHubPrNumbers: pocketOfPrNumbersUnfrozen});
}//fi }//fi
// Is this in use? // Is this in use?

34
website/api/models/Platform.js vendored Normal file
View File

@ -0,0 +1,34 @@
/**
* Platform.js
*
* @description :: A model definition represents a database table/collection.
* @docs :: https://sailsjs.com/docs/concepts/models-and-orm/models
*/
module.exports = {
attributes: {
// ╔═╗╦═╗╦╔╦╗╦╔╦╗╦╦ ╦╔═╗╔═╗
// ╠═╝╠╦╝║║║║║ ║ ║╚╗╔╝║╣ ╚═╗
// ╩ ╩╚═╩╩ ╩╩ ╩ ╩ ╚╝ ╚═╝╚═╝
currentUnfrozenGitHubPrNumbers: {
type: 'json',
description: 'An array containing the numbers of PRs to the fleetdm/fleet repo that can currently bypass MergeFreeze.',
example: [13638, 13447, 13673],
required: true,
}
// ╔═╗╔╦╗╔╗ ╔═╗╔╦╗╔═╗
// ║╣ ║║║╠╩╗║╣ ║║╚═╗
// ╚═╝╩ ╩╚═╝╚═╝═╩╝╚═╝
// ╔═╗╔═╗╔═╗╔═╗╔═╗╦╔═╗╔╦╗╦╔═╗╔╗╔╔═╗
// ╠═╣╚═╗╚═╗║ ║║ ║╠═╣ ║ ║║ ║║║║╚═╗
// ╩ ╩╚═╝╚═╝╚═╝╚═╝╩╩ ╩ ╩ ╩╚═╝╝╚╝╚═╝
},
};

View File

@ -62,6 +62,7 @@
"NewsletterSubscription": false, "NewsletterSubscription": false,
"VantaConnection": false, "VantaConnection": false,
"CertificateSigningRequest": false, "CertificateSigningRequest": false,
"Platform": false,
// ...and any other backend globals (e.g. `"Organization": false`) // ...and any other backend globals (e.g. `"Organization": false`)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
} }

View File

@ -40,6 +40,11 @@ module.exports.bootstrap = async function() {
var lastRunBootstrapInfo = await sails.helpers.fs.readJson(bootstrapLastRunInfoPath) var lastRunBootstrapInfo = await sails.helpers.fs.readJson(bootstrapLastRunInfoPath)
.tolerate('doesNotExist');// (it's ok if the file doesn't exist yet-- just keep going.) .tolerate('doesNotExist');// (it's ok if the file doesn't exist yet-- just keep going.)
let numberOfPlatformRecords = await Platform.count();
if(numberOfPlatformRecords > 1) {
throw new Error('Consistency error: More than one platform record exists. To accurately freeze and unfreeze GitHub pull requests when the main branch is frozen, only one of these records should exist. Number of platform records found'+numberOfPlatformRecords);
}
if (lastRunBootstrapInfo && lastRunBootstrapInfo.lastRunVersion === HARD_CODED_DATA_VERSION) { if (lastRunBootstrapInfo && lastRunBootstrapInfo.lastRunVersion === HARD_CODED_DATA_VERSION) {
sails.log('Skipping v'+HARD_CODED_DATA_VERSION+' bootstrap script... (because it\'s already been run)'); sails.log('Skipping v'+HARD_CODED_DATA_VERSION+' bootstrap script... (because it\'s already been run)');
sails.log('(last run on this computer: @ '+(new Date(lastRunBootstrapInfo.lastRunAt))+')'); sails.log('(last run on this computer: @ '+(new Date(lastRunBootstrapInfo.lastRunAt))+')');
@ -71,6 +76,8 @@ module.exports.bootstrap = async function() {
password: await sails.helpers.passwords.hashPassword('abc123') password: await sails.helpers.passwords.hashPassword('abc123')
}).fetch(); }).fetch();
// Note: We do not create a platform record to avoid potential consistency violations.
if (sails.config.custom.enableBillingFeatures) { if (sails.config.custom.enableBillingFeatures) {
let stripeCustomerId = await sails.helpers.stripe.saveBillingInfo.with({ let stripeCustomerId = await sails.helpers.stripe.saveBillingInfo.with({
emailAddress: adminUser.emailAddress emailAddress: adminUser.emailAddress