fleet/website/scripts/create-issues-for-todays-rituals.js
Eric 43f21baa86
Website: Update script to create GH issues for rituals in YAML files. (#15752)
Closes: #14246

Changes: 
- Added a new key to the rituals YAML configuration: `autoIssue.repo`.
This value should be a string that is the name of the GH repo that
issues for the ritual should be created in.
- Updated ritual validation in `build-static-content`.
- Added support for the "monthly" ritual frequency for rituals with an
`autoIssue` value.
- Updated the `create-issues-for-todays-rituals` script to create GitHub
issues for rituals.

---------

Co-authored-by: Mike McNeil <mikermcneil@users.noreply.github.com>
Co-authored-by: Sam Pfluger <108141731+Sampfluger88@users.noreply.github.com>
2024-01-15 12:53:53 -06:00

124 lines
6.0 KiB
JavaScript
Vendored

module.exports = {
friendlyName: 'Create issues for todays rituals',
description: '',
inputs: {
dry: { type: 'boolean', defaultsTo: false, description: 'Whether to do a dry run instead.' },
},
fn: async function ({ dry }) {
let path = require('path');
let YAML = require('yaml');
let topLvlRepoPath = path.resolve(sails.config.appPath, '../');
let baseHeaders = {// (for github api)
'User-Agent': 'Fleetie pie',
'Authorization': `token ${sails.config.custom.githubAccessToken}`
};
// Find all the files in the top level /handbook folder and it's sub-folders
let FILES_IN_HANDBOOK_FOLDER = await sails.helpers.fs.ls.with({
dir: path.join(topLvlRepoPath, '/handbook'),
depth: 3
});
// Filter the list of filenames to get the rituals YAML files.
let ritualYamlPaths = FILES_IN_HANDBOOK_FOLDER.filter((filePath)=>{
return _.endsWith(filePath, 'rituals.yml');
});
for (let ritualSource of ritualYamlPaths) {
// Load rituals
let pathToRituals = path.resolve(topLvlRepoPath, ritualSource);
let rituals = [];
let ritualsYml = await sails.helpers.fs.read(pathToRituals);
try {
rituals = YAML.parse(ritualsYml, { prettyErrors: true });
} catch (err) {
throw new Error(`Could not parse the YAMl for rituals at ${pathToRituals} on line ${err.linePos.start.line}. To resolve, make sure the YAML is valid, and try again: ` + err.stack);
}
for (let ritual of rituals) {
// For each ritual, we'll:
// - Convert the ritual's frequency into milliseconds.
// - Find out when we will be creating the next issue for the ritual.
// - Create an issue for the ritual if the ritual takes place in the next 24 hours.
if (!ritual.autoIssue) {// « Skip to the next ritual if automations aren't enabled.
continue;
}
let isItTimeToCreateANewIssue = false;// Default this value to false.
let ritualsFrequencyInMs = 0;
if(_.startsWith(ritual.frequency, 'Daily')){// Using _.startsWith() to handle frequencies with emoji ("Daily ⏰") and with out ("Daily")
ritualsFrequencyInMs = 1000 * 60 * 60 * 24;
} else if(ritual.frequency === 'Weekly'){
ritualsFrequencyInMs = 1000 * 60 * 60 * 24 * 7;
} else if(ritual.frequency === 'Biweekly'){
ritualsFrequencyInMs = 1000 * 60 * 60 * 24 * 7 * 2;
} else if(ritual.frequency === 'Triweekly'){
ritualsFrequencyInMs = 1000 * 60 * 60 * 24 * 7 * 3;
} else if (ritual.frequency === 'Monthly') {
// For monthly rituals, we will get the number of days in the previous month, and create a timestamp of the next time this ritual should be run.
let todaysDate = new Date();
let numberOfDaysInLastMonth = new Date(todaysDate.getFullYear(), todaysDate.getMonth(), 0).getDate();
ritualsFrequencyInMs = 1000 * 60 * 60 * 24 * numberOfDaysInLastMonth;
}
// Get a JS timestamp representing 12 PM UTC of the day this script is running.
let twelveHoursInMs = 1000 * 60 * 60 * 12;
let today = new Date();
let lastUTCNoonAt = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate(), 12, 0, 0, 0)).getTime();
// Get a JS timestamp representing 12:00 PM UTC of the day this ritual started.
let ritualStartedAt = new Date(ritual.startedOn).getTime() + twelveHoursInMs;
// Find out how many times this ritual has occurred.
let howManyRitualsCycles = (lastUTCNoonAt - ritualStartedAt ) / ritualsFrequencyInMs;
// Find out when the next issue will be created at
let nextIssueShouldBeCreatedAt = ritualStartedAt + ((Math.floor(howManyRitualsCycles) + 1) * ritualsFrequencyInMs);
// Get the amount of this ritual's cycle remaining.
let amountOfCycleRemainingTillNextRitual = (Math.floor(howManyRitualsCycles) - howManyRitualsCycles) + 1;
// If amountOfCycleRemainingTillNextRitual is 0, then it is time to create a new issue for this ritual (Note: This will probably never happen)
if(amountOfCycleRemainingTillNextRitual === 0 || amountOfCycleRemainingTillNextRitual === -0){
isItTimeToCreateANewIssue = true;
} else {
// Otherwise, get the number of milliseconds until the next issue for this ritual will be created.
let timeToNextRitualInMs = amountOfCycleRemainingTillNextRitual * ritualsFrequencyInMs;
// Since this script runs once a day at the same time, we'll create issues we'll create issues for
if(_.startsWith(ritual.frequency, 'Daily')) {// Using _.startsWith() to handle frequencies with emoji ("Daily ⏰") and with out ("Daily")
isItTimeToCreateANewIssue = true;
} else if(timeToNextRitualInMs < 86400000) {
// If the next occurance of this ritual is in less than 24 hours (before this script runs again), we'll create an issue for it.
isItTimeToCreateANewIssue = true;
}
}
// Skip to the next ritual if it isn't time yet.
if (!isItTimeToCreateANewIssue) {
sails.log.verbose(`Next issue for ${ritual.task} (${ritual.autoIssue.labels.join(',')}) will be created on ${new Date(nextIssueShouldBeCreatedAt)} (Started on: ${ritual.startedOn}, frequency: ${ritual.frequency})`);
continue;
}
// Create an issue with right labels and assignee, in the right repo.
if (!dry) {
let owner = 'fleetdm';
// [?] https://docs.github.com/en/rest/issues/issues#create-an-issue
await sails.helpers.http.post(`https://api.github.com/repos/${owner}/${ritual.autoIssue.repo}/issues`, {
title: ritual.task,
body: ritual.description + (ritual.moreInfoUrl ? ('\n\n> Read more at '+ritual.moreInfoUrl) : ''),
labels: ritual.autoIssue.labels,
assignees: [ ritual.dri ]
}, baseHeaders);
} else {
sails.log('Dry run: Would have created an issue for ritual:', ritual);
}
}//∞
}//∞
}
};