Skip to content

Commit 1b53fb4

Browse files
committed
refactor to better support CLI
1 parent afed556 commit 1b53fb4

File tree

7 files changed

+143
-97
lines changed

7 files changed

+143
-97
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ other
88

99
package-lock.json
1010

11-
.now
11+
.now
12+
.env

now.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010
".gitattributes"
1111
],
1212
"env": {
13-
"GHTOKEN":"@ghtoken"
13+
"ghtoken":"@ghtoken"
1414
}
1515
}

src/cli.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
const commitlintbot = require('./');
2+
3+
/*
4+
Running
5+
6+
env (cat .env) node src/cli.js "feat: awesome feature"
7+
gls src/* | entr env (cat .env) node src/cli.js "feat: awesome feature"
8+
9+
options:
10+
--report reports to github status check
11+
*/
12+
13+
(async function() {
14+
const commitmsg = process.argv[2];
15+
16+
const {clintConfig, czConfig} = getLHConfigPlaceholders();
17+
18+
const cliRunData = {
19+
title: commitmsg,
20+
clintConfig,
21+
czConfig,
22+
};
23+
const prData = {
24+
repo: 'GoogleChrome/lighthouse',
25+
srcRepo: 'GoogleChrome/lighthouse',
26+
sha: 'dba63a60d774d9f6fa1ef0974495bec96af2235c',
27+
pr: '10361',
28+
};
29+
const opts = {
30+
reportStatus: process.argv.includes('--report'),
31+
};
32+
33+
await commitlintbot(prData, cliRunData, opts);
34+
})();
35+
36+
function getLHConfigPlaceholders() {
37+
const clintConfig = {
38+
extends: ['cz'],
39+
rules: {
40+
'body-leading-blank': [1, 'always'],
41+
'body-tense': [1, 'always', ['present-imperative']],
42+
'footer-leading-blank': [1, 'always'],
43+
'footer-tense': [1, 'always', ['present-imperative']],
44+
'header-max-length': [2, 'always', 80],
45+
// 'lang': [0, 'always', 'eng'],
46+
'scope-case': [2, 'always', 'lowerCase'],
47+
'scope-empty': [0, 'never'],
48+
'subject-case': [1, 'always', 'lowerCase'],
49+
'subject-empty': [0, 'never'],
50+
'subject-full-stop': [2, 'never', '.'],
51+
// 'subject-tense': [1, 'always', ['present-imperative']],
52+
'type-case': [2, 'always', 'lowerCase'],
53+
'type-empty': [2, 'never'],
54+
// The scope-enum : defined in the cz-config
55+
// The 'type-enum': defined in the cz-config
56+
},
57+
};
58+
const czConfig = {
59+
allowBreakingChanges: ['core'],
60+
allowCustomScopes: true,
61+
scopes: [],
62+
types: [
63+
{value: 'new_audit', name: 'new_audit: A new audit'},
64+
{value: 'core', name: 'core: Driver, gather, (non-new) audits, LHR JSON, etc'},
65+
{value: 'tests', name: 'tests: Tests, smokehouse, etc'},
66+
{value: 'i18n', name: 'i18n: Internationalization'},
67+
{value: 'docs', name: 'docs: Documentation'},
68+
{value: 'deps', name: 'deps: Dependency bumps only'},
69+
{value: 'report', name: 'report: Report, UI, renderers'},
70+
{value: 'cli', name: 'cli: CLI stuff'},
71+
{value: 'clients', name: 'clients: Extension, DevTools, or LR stuff'},
72+
{value: 'misc', name: 'misc: Something else entirely'},
73+
],
74+
};
75+
return {clintConfig, czConfig};
76+
}

src/index.js

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,47 +17,55 @@ const czConfigFilename = `.cz-config.js`;
1717
const clintConfigFilename = 'commitlint.config.js';
1818

1919
const baseGithubData = {
20-
token: process.env.GHTOKEN, // (github oauth token: https://developer.github.com/v3/oauth)
20+
token: process.env.ghtoken, // (github oauth token: https://developer.github.com/v3/oauth)
2121
label: 'pr title lint'
2222
};
2323

24-
async function init(prData) {
25-
let status;
24+
async function gatherGithubData(githubData) {
25+
const apiFetches = [
26+
getPRTitle(githubData),
27+
getFileContents(githubData, clintConfigFilename),
28+
getFileContents(githubData, czConfigFilename)
29+
];
30+
let [title, clintConfigContent, czConfigContent] = await Promise.all(apiFetches);
31+
32+
// requireFromString: js file string => object
33+
const clintConfig = clintConfigContent && requireFromString(clintConfigContent);
34+
const czConfig = requireFromString(czConfigContent);
35+
36+
return {title, clintConfig, czConfig}
37+
}
38+
39+
async function main(prData, cliRunData = false, {reportStatus = true}) {
2640
try {
41+
let status;
2742
const githubData = Object.assign({}, baseGithubData, prData);
28-
status = new CommitStatus(githubData);
29-
await status.start('Linting the pull request title...').catch(handleCommitStatusFailure);
3043

31-
const lintOpts = {};
44+
status = reportStatus ? new CommitStatus(githubData) : new MockCommitStatus();
45+
await status.start('Linting the pull request title...').catch(handleCommitStatusFailure);
3246

33-
const apiFetches = [
34-
getPRTitle(githubData),
35-
getFileContents(githubData, clintConfigFilename),
36-
getFileContents(githubData, czConfigFilename)
37-
];
38-
let [title, clintConfigContent, czConfigContent] = await Promise.all(apiFetches);
47+
// Allow CLI use for local testing :p
48+
const {title, clintConfig, czConfig} = await (!cliRunData ?
49+
gatherGithubData(githubData) :
50+
Promise.resolve(cliRunData));
3951

40-
if (clintConfigContent) {
41-
lintOpts.clintConfig = requireFromString(clintConfigContent);
42-
}
43-
if (czConfigContent) {
44-
czConfigContent = requireFromString(czConfigContent)
45-
}
52+
const {report, reportObj} = await lint(title, clintConfig, czConfig);
4653

47-
const {report, reportObj} = await lint(title, lintOpts, czConfigContent);
4854

49-
const flatReport = report.join('. ');
55+
reportStatus && console.log('🌏 Reporting real status to GitHub: ', `https://api.github.com/repos/${prData.repo}/statuses/${prData.sha}`);
5056

5157
// Set status to passing
5258
if (reportObj.valid === true) {
53-
console.log(`> 🖋✅ Setting status: _passing_ (https://github.com/${githubData.repo}/pull/${githubData.pr})`);
59+
console.log(`> 🖋✅ _Passing_ (https://github.com/${githubData.repo}/pull/${githubData.pr})`);
5460
return status
5561
.pass('PR title is good to go, boss', generateURL(title, report))
5662
.catch(handleCommitStatusFailure);
5763
}
5864

5965
// Set status to failing
60-
console.log(`> 🖋❌ Setting status: _failing_ (https://github.com/${githubData.repo}/pull/${githubData.pr})`);
66+
console.log(`> 🖋❌ _Failing_ (https://github.com/${githubData.repo}/pull/${githubData.pr})`);
67+
68+
const flatReport = report.join('.\n');
6169
console.log(flatReport);
6270
const failureMsg = flatReport.slice(0, MAXIMUM_STATUS_LENGTH);
6371
return status.fail(failureMsg, generateURL(title, report)).catch(handleCommitStatusFailure);
@@ -74,7 +82,7 @@ async function init(prData) {
7482
}
7583
}
7684

77-
module.exports = init;
85+
module.exports = main;
7886

7987
function generateURL(prTitle, reportArr) {
8088
const outputStr = `
@@ -93,3 +101,9 @@ Expected PR title format is: \`{type}({optional-scope}): {subject}\`
93101
return `https://commitlintbot.now.sh/details/?msg=${encodeURIComponent(outputStr)}`;
94102
}
95103

104+
class MockCommitStatus {
105+
start (_) { return Promise.resolve(); }
106+
pass (_) { return Promise.resolve(); }
107+
fail (_) { return Promise.resolve(); }
108+
error (_) { return Promise.resolve(); }
109+
}

src/jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
module.exports = {
44
globals: {
5-
GHTOKEN: process.env.GHTOKEN,
5+
ghtoken: process.env.ghtoken,
66
},
77
};

src/lint.js

Lines changed: 23 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ const commitlint = require('@commitlint/core');
44
const mergeCZWithBaseConfig = require('commitlint-config-cz/lib/config').get;
55
const defaultClintConfig = require('./default-commitlint.config');
66

7-
async function lint(prTitle, lintOpts = {}, czConfig) {
7+
async function lint(prTitle, clintConfig = {}, czConfig) {
88
console.log(`> Linting: ${prTitle}`);
99

1010
// Use provided commitlint.config or fallback to our local preset
11-
const baseConfig = lintOpts.clintConfig || defaultClintConfig;
11+
const baseConfig = clintConfig || defaultClintConfig;
1212
baseConfig.extends = baseConfig.extends || [];
1313

1414
let mergedConfig;
@@ -30,73 +30,28 @@ async function lint(prTitle, lintOpts = {}, czConfig) {
3030
mergedConfig = baseConfig;
3131
}
3232

33-
const opts = await commitlint.load(mergedConfig);
34-
const reportObj = await commitlint.lint(prTitle, opts.rules);
35-
let report = await commitlint.format.formatResult(reportObj, {color: false});
36-
// drop weird helpURL https://github.com/conventional-changelog/commitlint/blob/master/docs/reference-api.md#usage
37-
report = report.slice(0, report.length - 2);
38-
return {reportObj, report};
39-
}
40-
41-
module.exports = lint;
33+
// HACK remove deprecated rules. Can be removed after existing PRs
34+
for (const deprecatedRule of ['body-tense', 'footer-tense', 'lang', 'subject-tense']) {
35+
delete mergedConfig.rules[deprecatedRule];
36+
}
4237

43-
// Run via
44-
// node lint.js "feat: awesome feature"
45-
// node lint.js "feat: awesome feature" --lh # --lh has to be argv[3]..
46-
//
47-
if (process.argv.length > 2 && process.argv[1].includes('lint.js')) {
48-
(async function() {
49-
if (process.argv[3] == '--lh') {
50-
const {lintOpts, czConfig} = getLHConfigPlaceholders();
51-
const {report} = await lint(process.argv[2], lintOpts, czConfig);
52-
process.stdout.write(report.join('\n') + '\n');
53-
} else {
54-
const {report} = await lint(process.argv[2],);
55-
process.stdout.write(report.join('\n') + '\n');
38+
const opts = await commitlint.load(mergedConfig);
39+
try {
40+
const reportObj = await commitlint.lint(prTitle, opts.rules);
41+
let report = await commitlint.format.formatResult(reportObj, {color: false});
42+
// drop weird helpURL https://github.com/conventional-changelog/commitlint/blob/master/docs/reference-api.md#usage
43+
report = report.slice(0, report.length - 2);
44+
return {reportObj, report};
45+
} catch (e) {
46+
return {
47+
reportObj: {
48+
valid: false,
49+
errors: [e.message],
50+
warnings: [],
51+
},
52+
report: [e.message]
5653
}
57-
})();
54+
}
5855
}
5956

60-
function getLHConfigPlaceholders() {
61-
const lintOpts = {
62-
clintConfig: {
63-
extends: ['cz'],
64-
rules: {
65-
'body-leading-blank': [1, 'always'],
66-
// 'body-tense': [1, 'always', ['present-imperative']],
67-
'footer-leading-blank': [1, 'always'],
68-
// 'footer-tense': [1, 'always', ['present-imperative']],
69-
'header-max-length': [2, 'always', 80],
70-
// 'lang': [0, 'always', 'eng'],
71-
'scope-case': [2, 'always', 'lowerCase'],
72-
'scope-empty': [0, 'never'],
73-
'subject-case': [1, 'always', 'lowerCase'],
74-
'subject-empty': [0, 'never'],
75-
'subject-full-stop': [2, 'never', '.'],
76-
// 'subject-tense': [1, 'always', ['present-imperative']],
77-
'type-case': [2, 'always', 'lowerCase'],
78-
'type-empty': [2, 'never'],
79-
// The scope-enum : defined in the cz-config
80-
// The 'type-enum': defined in the cz-config
81-
},
82-
}
83-
};
84-
const czConfig = {
85-
allowBreakingChanges: ['core'],
86-
allowCustomScopes: true,
87-
scopes: [],
88-
types: [
89-
{value: 'new_audit', name: 'new_audit: A new audit'},
90-
{value: 'core', name: 'core: Driver, gather, (non-new) audits, LHR JSON, etc'},
91-
{value: 'tests', name: 'tests: Tests, smokehouse, etc'},
92-
{value: 'i18n', name: 'i18n: Internationalization'},
93-
{value: 'docs', name: 'docs: Documentation'},
94-
{value: 'deps', name: 'deps: Dependency bumps only'},
95-
{value: 'report', name: 'report: Report, UI, renderers'},
96-
{value: 'cli', name: 'cli: CLI stuff'},
97-
{value: 'clients', name: 'clients: Extension, DevTools, or LR stuff'},
98-
{value: 'misc', name: 'misc: Something else entirely'}
99-
]
100-
};
101-
return {lintOpts, czConfig};
102-
}
57+
module.exports = lint;

src/server.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const indexGET = (request, response) => {
2121
};
2222

2323
const indexPOST = (request, response) => {
24-
let result;
24+
let prData;
2525
try {
2626
const {headers, body} = request;
2727

@@ -45,7 +45,7 @@ const indexPOST = (request, response) => {
4545
}
4646

4747
// pull out required info
48-
result = {
48+
prData = {
4949
repo: body.repository.full_name,
5050
srcRepo: body.pull_request.head.repo.full_name,
5151
sha: body.pull_request.head.sha,
@@ -60,7 +60,7 @@ const indexPOST = (request, response) => {
6060
queue.add(async _ => {
6161
log.info(`> Calling commitlint bot with received webhook data`);
6262
try {
63-
const {status, data} = await commitlintbot(result);
63+
const {status, data} = await commitlintbot(prData);
6464
// Some status API call failure
6565
if (data.error) {
6666
if (status === 404)

0 commit comments

Comments
 (0)