scripts/commit-lint/lint.js (79 lines of code) (raw):

import read from '@commitlint/read'; import lint from '@commitlint/lint'; import format from '@commitlint/format'; import config from '@commitlint/config-conventional'; // You can test the script by setting these environment variables const { CI_MERGE_REQUEST_DIFF_BASE_SHA, // refers to the main branch CI_MERGE_REQUEST_SQUASH_ON_MERGE, // true if the squash MR checkbox is ticked CI_MERGE_REQUEST_TITLE, // MR Title CI_MERGE_REQUEST_EVENT_TYPE, // equal to 'merge_train' if the pipeline is a merge train pipeline CI, // true when script is run in a CI/CD pipeline LAST_MR_COMMIT, // This variable is created by `lint.sh` script. It represents the MR commit that's direct parent of the newly created merge commit. } = process.env; const urlSemanticRelease = 'https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/blob/main/docs/developer/commits.md'; // See rule docs https://commitlint.js.org/#/reference-rules const customRules = { 'header-max-length': [2, 'always', 72], 'body-leading-blank': [2, 'always'], 'footer-leading-blank': [2, 'always'], 'subject-case': [0], 'body-max-line-length': [1, 'always', 100], }; async function getCommitsInMr() { const diffBaseSha = CI_MERGE_REQUEST_DIFF_BASE_SHA; const sourceBranchSha = LAST_MR_COMMIT; const messages = await read({ from: diffBaseSha, to: sourceBranchSha }); return messages; } const messageMatcher = r => r.test.bind(r); async function isConventional(message) { return lint( message, { ...config.rules, ...customRules }, { defaultIgnores: false, ignores: [ messageMatcher(/^[Rr]evert .*/), messageMatcher(/^(?:fixup|squash)!/), messageMatcher(/^Merge branch/), messageMatcher(/^\d+\.\d+\.\d+/), ], }, ); } async function lintMr() { const commits = await getCommitsInMr(); // When MR is set to squash, but it's not yet being merged, we check the MR Title if ( CI_MERGE_REQUEST_SQUASH_ON_MERGE === 'true' && CI_MERGE_REQUEST_EVENT_TYPE !== 'merge_train' ) { console.log( 'INFO: The MR is set to squash. We will lint the MR Title (used as the commit message by default).', ); return isConventional(CI_MERGE_REQUEST_TITLE).then(Array.of); } console.log('INFO: Checking all commits that will be added by this MR.'); return Promise.all(commits.map(commit => isConventional(commit))); } async function run() { if (!CI) { console.error('This script can only run in GitLab CI.'); process.exit(1); } if (!LAST_MR_COMMIT) { console.error( 'LAST_MR_COMMIT environment variable is not present. Make sure this script is run from `lint.sh`', ); process.exit(1); } const results = await lintMr(); console.error(format({ results }, { helpUrl: urlSemanticRelease })); const numOfErrors = results.reduce((acc, result) => acc + result.errors.length, 0); if (numOfErrors !== 0) { process.exit(1); } } run().catch(err => { console.error(err); process.exit(1); });