Skip to content

Commit

Permalink
build(repo): validate commit messages (#1731)
Browse files Browse the repository at this point in the history
* build(repo): validate commit messages

* chore(repo): include deps-dev in scopes

* chore(repo): handle merge commits

* chore(repo): parents might be null
  • Loading branch information
P0lip authored Oct 29, 2021
1 parent 9529495 commit 953951e
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 4 deletions.
3 changes: 1 addition & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ commands:
steps:
- run:
name: Lint commit messages
command: |
echo "$(git log -1 --pretty=format:"%s")" | npx commitlint
command: node ./scripts/lint-commit-messages.mjs

test-node:
parameters:
Expand Down
2 changes: 1 addition & 1 deletion .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx --no-install commitlint --edit $1
yarn commitlint --edit $1
9 changes: 9 additions & 0 deletions commitlint.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
/*eslint-env node*/
const fs = require('fs');
const path = require('path');

const scopes = ['repo', 'test-harness', 'deps-dev', ...fs.readdirSync(path.join(__dirname, './packages'))];

module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'scope-empty': [2, 'never'],
'scope-enum': [2, 'always', scopes],
},
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"node": ">=12"
},
"scripts": {
"clean": "rimraf packages/*/{dist,.cache}",
"clean": "rimraf .cache packages/*/{dist,.cache}",
"prebuild": "yarn workspace @stoplight/spectral-ruleset-migrator prebuild",
"build": "tsc --build ./tsconfig.build.json",
"postbuild": "yarn workspace @stoplight/spectral-cli postbuild",
Expand Down Expand Up @@ -62,6 +62,7 @@
"devDependencies": {
"@commitlint/cli": "^13.2.0",
"@commitlint/config-conventional": "^12.1.4",
"@octokit/core": "^3.5.1",
"@types/jest": "^27.0.2",
"@types/jest-when": "^2.7.3",
"@types/karma": "^6.3.1",
Expand Down
62 changes: 62 additions & 0 deletions scripts/lint-commit-messages.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import * as process from 'node:process';
import * as child_process from 'node:child_process';
import { promisify } from 'node:util';
import * as assert from 'node:assert';
import { Octokit } from '@octokit/core';
import chalk from 'chalk';

if (!process.env.CI_PULL_REQUEST) {
// not a PR
process.exit(0);
}

const execAsync = promisify(child_process.exec);

const octokit = new Octokit({ auth: process.env.GH_TOKEN });

const PULL_REQUEST_NUMBER = Number(process.env.CI_PULL_REQUEST.slice(process.env.CI_PULL_REQUEST.lastIndexOf('/') + 1));
assert.ok(!Number.isNaN(PULL_REQUEST_NUMBER), `Could not find valid PR Number: ${PULL_REQUEST_NUMBER}`);

const OPTIONS = {
owner: 'stoplightio',
repo: 'spectral',
id: PULL_REQUEST_NUMBER,
};

const pullRequest = await octokit.request('GET /repos/{owner}/{repo}/pulls/{id}', OPTIONS);
assert.ok(pullRequest.status >= 200 && pullRequest.status < 300);

await lint(pullRequest.data.title, 'Your PR title is invalid');

const autoMergeCommitTitle = pullRequest.data.auto_merge?.commit_title;

if (typeof autoMergeCommitTitle === 'string') {
await lint(pullRequest.data.title, 'Your auto-merge message is invalid');
}

const commits = await octokit.request('GET /repos/{owner}/{repo}/pulls/{id}/commits', OPTIONS);
assert.ok(commits.status >= 200 && commits.status < 300);

for (const { commit } of commits.data) {
if (Array.isArray(commit.parents) && commit.parents.length > 1) {
// possibly a merge commit, carry on
continue;
}

await lint(commit.message);
}

process.stdout.write(chalk.green('✔️ All good. Your commit messages are valid.\n'));

async function lint(title, header) {
try {
await execAsync(`echo "${title}" | yarn commitlint`);
} catch (e) {
if (header) {
process.stderr.write(chalk.redBright(`✖ ${header}\n`));
}

process.stderr.write(chalk.redBright(e.stdout ?? e.message));
process.exit(1);
}
}
91 changes: 91 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1268,6 +1268,77 @@
"@nodelib/fs.scandir" "2.1.3"
fastq "^1.6.0"

"@octokit/auth-token@^2.4.4":
version "2.4.5"
resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.5.tgz#568ccfb8cb46f36441fac094ce34f7a875b197f3"
integrity sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==
dependencies:
"@octokit/types" "^6.0.3"

"@octokit/core@^3.5.1":
version "3.5.1"
resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.5.1.tgz#8601ceeb1ec0e1b1b8217b960a413ed8e947809b"
integrity sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==
dependencies:
"@octokit/auth-token" "^2.4.4"
"@octokit/graphql" "^4.5.8"
"@octokit/request" "^5.6.0"
"@octokit/request-error" "^2.0.5"
"@octokit/types" "^6.0.3"
before-after-hook "^2.2.0"
universal-user-agent "^6.0.0"

"@octokit/endpoint@^6.0.1":
version "6.0.12"
resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658"
integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==
dependencies:
"@octokit/types" "^6.0.3"
is-plain-object "^5.0.0"
universal-user-agent "^6.0.0"

"@octokit/graphql@^4.5.8":
version "4.6.4"
resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.6.4.tgz#0c3f5bed440822182e972317122acb65d311a5ed"
integrity sha512-SWTdXsVheRmlotWNjKzPOb6Js6tjSqA2a8z9+glDJng0Aqjzti8MEWOtuT8ZSu6wHnci7LZNuarE87+WJBG4vg==
dependencies:
"@octokit/request" "^5.6.0"
"@octokit/types" "^6.0.3"
universal-user-agent "^6.0.0"

"@octokit/openapi-types@^8.2.1":
version "8.2.1"
resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-8.2.1.tgz#102e752a7378ff8d21057c70fd16f1c83856d8c5"
integrity sha512-BJz6kWuL3n+y+qM8Pv+UGbSxH6wxKf/SBs5yzGufMHwDefsa+Iq7ZGy1BINMD2z9SkXlIzk1qiu988rMuGXEMg==

"@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0":
version "2.1.0"
resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677"
integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==
dependencies:
"@octokit/types" "^6.0.3"
deprecation "^2.0.0"
once "^1.4.0"

"@octokit/request@^5.6.0":
version "5.6.0"
resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.0.tgz#6084861b6e4fa21dc40c8e2a739ec5eff597e672"
integrity sha512-4cPp/N+NqmaGQwbh3vUsYqokQIzt7VjsgTYVXiwpUP2pxd5YiZB2XuTedbb0SPtv9XS7nzAKjAuQxmY8/aZkiA==
dependencies:
"@octokit/endpoint" "^6.0.1"
"@octokit/request-error" "^2.1.0"
"@octokit/types" "^6.16.1"
is-plain-object "^5.0.0"
node-fetch "^2.6.1"
universal-user-agent "^6.0.0"

"@octokit/types@^6.0.3", "@octokit/types@^6.16.1":
version "6.18.1"
resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.18.1.tgz#a6db178536e649fd5d67a7b747754bcc43940be4"
integrity sha512-5YsddjO1U+xC8ZYKV8yZYebW55PCc7qiEEeZ+wZRr6qyclynzfyD65KZ5FdtIeP0/cANyFaD7hV69qElf1nMsQ==
dependencies:
"@octokit/openapi-types" "^8.2.1"

"@rollup/plugin-commonjs@^20.0.0":
version "20.0.0"
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-20.0.0.tgz#3246872dcbcb18a54aaa6277a8c7d7f1b155b745"
Expand Down Expand Up @@ -2101,6 +2172,11 @@ [email protected], base64id@~2.0.0:
resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==

before-after-hook@^2.2.0:
version "2.2.2"
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e"
integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==

binary-extensions@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
Expand Down Expand Up @@ -2910,6 +2986,11 @@ [email protected], dependency-graph@~0.11.0:
resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.11.0.tgz#ac0ce7ed68a54da22165a85e97a01d53f5eb2e27"
integrity sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==

deprecation@^2.0.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==

des.js@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc"
Expand Down Expand Up @@ -4285,6 +4366,11 @@ is-plain-obj@^1.1.0:
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=

is-plain-object@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==

is-potential-custom-element-name@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5"
Expand Down Expand Up @@ -7396,6 +7482,11 @@ unicode-property-aliases-ecmascript@^1.0.4:
resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4"
integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==

universal-user-agent@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee"
integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==

universalify@^0.1.0, universalify@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
Expand Down

0 comments on commit 953951e

Please sign in to comment.