Revert "Revert "Use DangerJS for commenting" (#1027)"

This reverts commit 88026cb756.
This commit is contained in:
Hugo 2020-11-23 08:50:34 +00:00 committed by GitHub
parent 88026cb756
commit 4403c10e5b
7 changed files with 753 additions and 188 deletions

View file

@ -25,7 +25,7 @@ jobs:
- name: Install Dependencies - name: Install Dependencies
run: npm install run: npm install
- name: Validate data.js - name: Validate data.js using DangerJS
run: node ./scripts/data-validate.js run: npx danger ci
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}

57
dangerfile.js Normal file
View file

@ -0,0 +1,57 @@
/* eslint-disable import/no-extraneous-dependencies */
const { danger, fail, markdown, message, schedule } = require('danger');
const validate = require('./scripts/data-validate');
const DATA_FILE = 'src/data.js';
async function main() {
if (!danger.git.modified_files.includes(DATA_FILE)) {
message(`No changes in \`${DATA_FILE}\``);
return;
}
const diff = await danger.git.diffForFile(DATA_FILE);
// eslint-disable-next-line no-eval
const masterData = eval(diff.before);
const { data: changedData, errorMsgs, failedUrls } = await validate(
masterData
);
// If there are errors, will fail the action & add a comment detailing the issues
if (errorMsgs.length) {
fail(`There are ${errorMsgs.length} validation error(s)`);
markdown(
`### Validation Issues\n${errorMsgs.map(msg => `- ${msg}`).join('\n')}`
);
}
if (failedUrls.length) {
fail(`There are ${failedUrls.length} failing URL(s)`);
markdown(
`### Failing URLs\n${failedUrls
.map(({ url, error, statusCode }) => {
if (error)
return `- URL, ${url}, failed with error: ${error.message}`;
return `- URL, ${url}, failed with status code: ${statusCode}`;
})
.join('\n')}`
);
}
// If there are no errors, will leave an "all-clear" comment with relevant URLs (to ease a potential manual check)
if (!errorMsgs.length && !failedUrls.length && changedData.length) {
message('Automatic validation checks succeeded', { icon: '✅' });
// Comment with the URLs of users that have changed
// for easy access, way easier than taking a screenshot
markdown(
`### Changed URLs\n${changedData
.map(({ name, url }) => `- ${name}, ${url}`)
.join('\n')}`
);
}
}
schedule(main);

734
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -12,9 +12,6 @@
"node": ">= 12" "node": ">= 12"
}, },
"dependencies": { "dependencies": {
"@actions/core": "^1.2.1",
"@actions/exec": "^1.0.3",
"@actions/github": "^2.0.1",
"@hapi/joi": "^17.0.2", "@hapi/joi": "^17.0.2",
"country-emoji": "^1.5.0", "country-emoji": "^1.5.0",
"esm": "^3.2.25", "esm": "^3.2.25",
@ -45,6 +42,7 @@
"devDependencies": { "devDependencies": {
"@architect/sandbox": "^1.6.0", "@architect/sandbox": "^1.6.0",
"babel-eslint": "^9.0.0", "babel-eslint": "^9.0.0",
"danger": "^10.1.1",
"eslint": "^5.16.0", "eslint": "^5.16.0",
"eslint-config-airbnb": "^17.1.1", "eslint-config-airbnb": "^17.1.1",
"eslint-config-prettier": "^4.3.0", "eslint-config-prettier": "^4.3.0",

View file

@ -1,43 +1,48 @@
const core = require('@actions/core'); const { Schema, getStatusCode } = require('./utils.js');
const {
getMasterData,
Schema,
getStatusCode,
communicateValidationOutcome,
} = require('./utils.js');
const srcData = require('../src/data.js'); const srcData = require('../src/data.js');
async function main() { async function main(masterData = []) {
// on master branch will be empty array const masterDataUrls = masterData.map(d => d.url);
const masterDataUrls = (await getMasterData()).map(d => d.url);
// so here data will be an array with all users // so here data will be an array with all users
const data = srcData.filter(d => !masterDataUrls.includes(d.url)); const data = srcData.filter(d => !masterDataUrls.includes(d.url));
const errors = data const errors = data
.map(person => Schema.validate(person)) .map(person =>
Schema.validate(person, {
abortEarly: false,
})
)
.filter(v => v.error) .filter(v => v.error)
.map(v => v.error); .map(v => v.error);
const errorMsgs = [];
errors.forEach(e => { errors.forEach(e => {
core.error(e._original.name || e._original.url); e.details.forEach(d =>
e.details.forEach(d => core.error(d.message)); errorMsgs.push(`${e._original.name || e._original.url}: ${d.message}`)
);
}); });
/**
* @type {{url: string, statusCode?: number, error?: Error}[]}
*/
const failedUrls = []; const failedUrls = [];
for (const { url } of data) { for (const { url } of data) {
try { try {
const statusCode = await getStatusCode(url); const statusCode = await getStatusCode(url);
if (statusCode < 200 || statusCode >= 400) { if (statusCode < 200 || statusCode >= 400) {
core.error(`Ping to "${url}" failed with status: ${statusCode}`); failedUrls.push({ url, statusCode });
failedUrls.push(url);
} }
} catch (e) { } catch (e) {
core.error(`Ping to "${url}" failed with error: ${e}`); failedUrls.push({ url, error: e });
failedUrls.push(url);
} }
} }
await communicateValidationOutcome(errors, failedUrls, data); return {
failedUrls,
errorMsgs,
data,
};
} }
main(); module.exports = main;

View file

@ -1,5 +0,0 @@
/**
* this is a stub file, do not edit it
* see `scripts/utils.js` -> `getMasterData`
*/
module.exports = [];

View file

@ -1,55 +1,8 @@
const exec = require('@actions/exec');
const core = require('@actions/core');
const github = require('@actions/github');
const Joi = require('@hapi/joi'); const Joi = require('@hapi/joi');
const http = require('http'); const http = require('http');
const https = require('https'); const https = require('https');
const flags = require('./flags.js'); const flags = require('./flags.js');
async function getCurrentBranchName() {
let myOutput = '';
let myError = '';
const options = {
silent: true,
listeners: {
stdout: data => (myOutput += data.toString()),
stderr: data => (myError += data.toString()),
},
};
await exec.exec('git rev-parse --abbrev-ref HEAD', [], options);
return myOutput.trim();
}
/** on master branch will return an empty array */
module.exports.getMasterData = async function() {
const options = { silent: true };
const curentBranchName = await getCurrentBranchName();
// when on a branch/PR different from master
// will populate scripts/masterData.js with src/data.js from master
if (curentBranchName !== 'master') {
core.info('Executing action on branch different from master');
await exec.exec('mv src/data.js src/tmpData.js', [], options);
await exec.exec('git fetch origin master', [], options);
await exec.exec('git restore --source=FETCH_HEAD src/data.js', [], options);
await exec.exec('mv src/data.js scripts/masterData.js', [], options);
await exec.exec('mv src/tmpData.js src/data.js', [], options);
} else {
core.info('Executing action on master branch');
}
// eslint-disable-next-line global-require
const masterData = require('./masterData.js');
// restore `scripts/masterData.js` after was loaded
if (curentBranchName !== 'master') {
await exec.exec('git restore scripts/masterData.js', [], options);
}
return masterData;
};
module.exports.Schema = Joi.object({ module.exports.Schema = Joi.object({
name: Joi.string().required(), name: Joi.string().required(),
description: Joi.string().required(), description: Joi.string().required(),
@ -85,48 +38,3 @@ module.exports.getStatusCode = function(url) {
.on('error', err => reject(err)); .on('error', err => reject(err));
}); });
}; };
// If there are errors, will fail the action & add a comment detailing the issues
// If there are no errors, will leave an "all-clear" comment with relevant URLs (to ease a potential manual check)
module.exports.communicateValidationOutcome = async function(
errors,
failedUrls,
changedData
) {
let comment = '';
if (errors.length || failedUrls.length) {
core.setFailed('Action failed with errors, see logs & comment');
comment += [
'🚨 We have detected the following issues, let us (contributors) know if you need support or clarifications:',
...errors.map(e => `- ${e.message}`),
...failedUrls.map(url => `- URL is invalid: ${url}`),
].join('\n');
} else {
comment += [
'✅ Automatic validation checks succeeded for:',
// Comment with the URLs of users that have changed
// for easy access, way easier than taking a screenshot
...changedData.map(({ name, url }) => `- ${name}, ${url}`),
].join('\n');
}
const { GITHUB_TOKEN } = process.env;
const { context } = github;
if (!GITHUB_TOKEN || !context.payload.pull_request) {
core.error(
'Cannot add a comment if GITHUB_TOKEN or context.payload.pull_request is not set'
);
core.info(`Comment contents:\n${comment}`);
return;
}
const pullRequestNumber = context.payload.pull_request.number;
const octokit = new github.GitHub(GITHUB_TOKEN);
await octokit.issues.createComment({
...context.repo,
issue_number: pullRequestNumber,
body: comment,
});
};