@thisismanta/semantic-version 6.0.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -25
- package/lib/auto-npm-version.js +27 -22
- package/lib/run.d.ts +1 -0
- package/lib/run.js +44 -0
- package/package.json +3 -6
- package/lib/install-git-hooks.d.ts +0 -1
- package/lib/install-git-hooks.js +0 -89
package/README.md
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
# `npx lint-commit-message <path>`
|
|
2
|
+
|
|
3
|
+
The `<path>` must point to a text file containing commit message that complies with the following pattern:
|
|
2
4
|
|
|
3
5
|
```
|
|
4
6
|
<type>[!]: <subject>
|
|
@@ -8,9 +10,18 @@ Where
|
|
|
8
10
|
- `!` indicates that the commit contains breaking changes.
|
|
9
11
|
- `<subject>` is the actual commit message where the first word must be written in lower cases.
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
> Usage example with [**lefthook**](https://www.npmjs.com/package/lefthook)
|
|
14
|
+
> ```yml
|
|
15
|
+
> # lefthook.yml
|
|
16
|
+
> commit-msg:
|
|
17
|
+
> commands:
|
|
18
|
+
> lint:
|
|
19
|
+
> run: npx lint-commit-message {1}
|
|
20
|
+
> ```
|
|
21
|
+
|
|
22
|
+
# `npx auto-npm-version`
|
|
12
23
|
|
|
13
|
-
|
|
24
|
+
This command is supposed to be run on CI, such as **GitHub Actions**. It will run `npm version <new-version>`, which `<new-version>` is automatically derived from your commit messages according to the table below and then it creates a new entry on [**GitHub releases**](https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases).
|
|
14
25
|
|
|
15
26
|
|Commit message type|Post-commit command|
|
|
16
27
|
|---|---|
|
|
@@ -19,25 +30,24 @@ Additionally, you can run `npx auto-npm-version` on **GitHub Actions** to trigge
|
|
|
19
30
|
|`fix`|`npm version patch`|
|
|
20
31
|
|Others|Does not run `npm version`|
|
|
21
32
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
```
|
|
33
|
+
> Usage example with **GitHub Actions**
|
|
34
|
+
> ```yml
|
|
35
|
+
> on:
|
|
36
|
+
> push:
|
|
37
|
+
> branches: [master]
|
|
38
|
+
> jobs:
|
|
39
|
+
> release:
|
|
40
|
+
> runs-on: ubuntu-latest
|
|
41
|
+
> steps:
|
|
42
|
+
> - uses: actions/checkout@v4
|
|
43
|
+
> with:
|
|
44
|
+
> fetch-depth: 0 # Ensure Git tags are fetched
|
|
45
|
+
> - uses: actions/setup-node@v4
|
|
46
|
+
> with:
|
|
47
|
+
> node-version-file: 'package.json'
|
|
48
|
+
> cache: npm
|
|
49
|
+
> - run: npm ci # Install semantic-version as part of the dependencies
|
|
50
|
+
> - run: npx auto-npm-version
|
|
51
|
+
> env:
|
|
52
|
+
> GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Make it possible to create a new release using GitHub API
|
|
53
|
+
> ```
|
package/lib/auto-npm-version.js
CHANGED
|
@@ -27,9 +27,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
const semver_1 = __importDefault(require("semver"));
|
|
30
|
-
const execa_1 = require("execa");
|
|
31
30
|
const github = __importStar(require("@actions/github"));
|
|
32
31
|
const index_1 = require("./index");
|
|
32
|
+
const run_1 = require("./run");
|
|
33
33
|
const debug_1 = require("./debug");
|
|
34
34
|
main();
|
|
35
35
|
async function main() {
|
|
@@ -39,14 +39,14 @@ async function main() {
|
|
|
39
39
|
}
|
|
40
40
|
// Set up Git commit author for further use in "npm version" and "git push" command
|
|
41
41
|
// See https://github.com/actions/checkout#push-a-commit-using-the-built-in-token
|
|
42
|
-
if (!(await run(`git config user.name`).catch(() => ''))) {
|
|
43
|
-
await run(`git config user.name ${github.context.payload.pusher?.name || github.context.actor}`);
|
|
44
|
-
await run(`git config user.email ${github.context.payload.pusher?.email || 'github-actions@github.com'}`);
|
|
42
|
+
if (!(await (0, run_1.run)(`git config user.name`).catch(() => ''))) {
|
|
43
|
+
await (0, run_1.run)(`git config user.name ${github.context.payload.pusher?.name || github.context.actor}`);
|
|
44
|
+
await (0, run_1.run)(`git config user.email ${github.context.payload.pusher?.email || 'github-actions@github.com'}`);
|
|
45
45
|
}
|
|
46
|
-
const remote = await run(`git remote`) || 'origin';
|
|
46
|
+
const remote = await (0, run_1.run)(`git remote`) || 'origin';
|
|
47
47
|
// Check if the given GITHUB_TOKEN has the permission to push to the repository
|
|
48
48
|
// See https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#configuring-the-default-github_token-permissions
|
|
49
|
-
await run(`git push --dry-run ${remote}`);
|
|
49
|
+
await (0, run_1.run)(`git push --dry-run ${remote}`);
|
|
50
50
|
const lastVersion = await getLastVersion();
|
|
51
51
|
(0, debug_1.debug)('lastVersion »', JSON.stringify(lastVersion));
|
|
52
52
|
if (!lastVersion) {
|
|
@@ -61,8 +61,8 @@ async function main() {
|
|
|
61
61
|
console.log('Done without a new version');
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
|
-
await run(`npm version --git-tag-version ${releaseType}`);
|
|
65
|
-
await run(`git push --follow-tags ${remote}`);
|
|
64
|
+
await (0, run_1.run)(`npm version --git-tag-version ${releaseType}`);
|
|
65
|
+
await (0, run_1.run)(`git push --follow-tags ${remote}`);
|
|
66
66
|
const nextVersion = await getLastVersion();
|
|
67
67
|
(0, debug_1.debug)('nextVersion »', JSON.stringify(nextVersion));
|
|
68
68
|
console.log(`Created tag v${nextVersion}`);
|
|
@@ -82,19 +82,18 @@ async function main() {
|
|
|
82
82
|
(0, debug_1.debug)('releaseCreationRespond »', JSON.stringify(releaseCreationRespond, null, 2));
|
|
83
83
|
console.log('Done with a new release at', releaseCreationRespond.data.html_url);
|
|
84
84
|
}
|
|
85
|
-
async function run(command) {
|
|
86
|
-
(0, debug_1.debug)(command);
|
|
87
|
-
const { stdout } = await (0, execa_1.execaCommand)(command);
|
|
88
|
-
(0, debug_1.debug)(stdout);
|
|
89
|
-
return stdout;
|
|
90
|
-
}
|
|
91
85
|
async function getLastVersion() {
|
|
92
|
-
|
|
93
|
-
|
|
86
|
+
const versionFromGit = await (0, run_1.run)('git describe --tags --abbrev=0').catch(() => null);
|
|
87
|
+
const versionFromPackageJSON = JSON.parse(await (0, run_1.run)('npm pkg get version'));
|
|
88
|
+
const versions = [versionFromGit, versionFromPackageJSON]
|
|
89
|
+
.map(version => semver_1.default.valid(version))
|
|
90
|
+
.filter((version) => !!version);
|
|
91
|
+
// Choose the higher version
|
|
92
|
+
return semver_1.default.sort(versions).pop();
|
|
94
93
|
}
|
|
95
94
|
async function getGitHistory(version) {
|
|
96
|
-
const tagFound = !!(await run(`git tag --list v${version}`));
|
|
97
|
-
return await run(`git --no-pager log ${tagFound ? `v${version}..HEAD` : ''} --format=%H%s`);
|
|
95
|
+
const tagFound = !!(await (0, run_1.run)(`git tag --list v${version}`));
|
|
96
|
+
return await (0, run_1.run)(`git --no-pager log ${tagFound ? `v${version}..HEAD` : ''} --format=%H%s`);
|
|
98
97
|
}
|
|
99
98
|
function getCommits(gitLog) {
|
|
100
99
|
return gitLog
|
|
@@ -111,10 +110,16 @@ function getCommits(gitLog) {
|
|
|
111
110
|
});
|
|
112
111
|
}
|
|
113
112
|
function getReleaseType(commits) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
113
|
+
if (commits.find(({ breaking }) => breaking)) {
|
|
114
|
+
return 'major';
|
|
115
|
+
}
|
|
116
|
+
if (commits.find(({ type }) => type === 'feat')) {
|
|
117
|
+
return 'minor';
|
|
118
|
+
}
|
|
119
|
+
if (commits.find(({ type }) => type === 'fix' || type === 'build')) {
|
|
120
|
+
return 'patch';
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
118
123
|
}
|
|
119
124
|
function getReleaseNote(commits) {
|
|
120
125
|
const groups = {
|
package/lib/run.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function run(command: string): Promise<string>;
|
package/lib/run.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.run = void 0;
|
|
27
|
+
const cp = __importStar(require("child_process"));
|
|
28
|
+
const debug_1 = require("./debug");
|
|
29
|
+
function run(command) {
|
|
30
|
+
(0, debug_1.debug)(command);
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
cp.exec(command, (error, stdout, stderr) => {
|
|
33
|
+
if (error) {
|
|
34
|
+
reject(error);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
const output = (stdout + stderr).trim();
|
|
38
|
+
(0, debug_1.debug)(output);
|
|
39
|
+
resolve(output);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
exports.run = run;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thisismanta/semantic-version",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0",
|
|
4
4
|
"author": "Anantachai Saothong <thisismanta@gmail.com>",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"repository": {
|
|
@@ -24,23 +24,20 @@
|
|
|
24
24
|
"test": "jest",
|
|
25
25
|
"build": "rm -rf lib && tsc",
|
|
26
26
|
"preversion": "npm run build",
|
|
27
|
-
"version": "npm publish --access public"
|
|
28
|
-
"postinstall": "node ./lib/install-git-hooks.js",
|
|
29
|
-
"prepare": "husky install"
|
|
27
|
+
"version": "npm publish --access public"
|
|
30
28
|
},
|
|
31
29
|
"devDependencies": {
|
|
32
30
|
"@types/jest": "^29.5.11",
|
|
33
31
|
"@types/node": "^20.0.0",
|
|
34
32
|
"@types/semver": "^7.5.6",
|
|
35
33
|
"jest": "^29.7.0",
|
|
34
|
+
"lefthook": "^1.6.1",
|
|
36
35
|
"ts-jest": "^29.1.1",
|
|
37
36
|
"ts-node": "^10.9.2",
|
|
38
37
|
"typescript": "^5.3.3"
|
|
39
38
|
},
|
|
40
39
|
"dependencies": {
|
|
41
40
|
"@actions/github": "^6.0.0",
|
|
42
|
-
"execa": "npm:@esm2cjs/execa@^6.1.1-cjs.1",
|
|
43
|
-
"husky": "^8.0.3",
|
|
44
41
|
"semver": "^7.5.4"
|
|
45
42
|
},
|
|
46
43
|
"jest": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/lib/install-git-hooks.js
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
const fs = __importStar(require("fs/promises"));
|
|
27
|
-
const fp = __importStar(require("path"));
|
|
28
|
-
const execa_1 = require("execa");
|
|
29
|
-
const debug_1 = require("./debug");
|
|
30
|
-
main();
|
|
31
|
-
const packageName = require('../package.json').name;
|
|
32
|
-
async function main() {
|
|
33
|
-
const currentDirectoryPath = process.cwd();
|
|
34
|
-
(0, debug_1.debug)('currentDirectoryPath »', currentDirectoryPath);
|
|
35
|
-
const gitDirectoryPath = await findGitDirectoryPath(currentDirectoryPath);
|
|
36
|
-
(0, debug_1.debug)('gitDirectoryPath »', gitDirectoryPath);
|
|
37
|
-
if (!gitDirectoryPath) {
|
|
38
|
-
throw new Error('Could not find a Git directory.');
|
|
39
|
-
}
|
|
40
|
-
const packageJSON = JSON.parse(await fs.readFile(fp.join(gitDirectoryPath, 'package.json'), 'utf-8'));
|
|
41
|
-
if (packageJSON.name === packageName) {
|
|
42
|
-
console.warn('Skip installing Git hooks as it is supposed to be done on a consumer repository.');
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
console.log('Installing Husky');
|
|
46
|
-
await (0, execa_1.execaCommand)('npx husky install', { cwd: gitDirectoryPath });
|
|
47
|
-
const huskyDirectoryPath = fp.resolve(gitDirectoryPath, '.husky');
|
|
48
|
-
(0, debug_1.debug)('huskyDirectoryPath »', huskyDirectoryPath);
|
|
49
|
-
await fs.access(huskyDirectoryPath);
|
|
50
|
-
await upsert(fp.join(huskyDirectoryPath, 'commit-msg'), 'npx lint-commit-message ${1}');
|
|
51
|
-
console.log('Done adding Git hooks.');
|
|
52
|
-
}
|
|
53
|
-
async function findGitDirectoryPath(path) {
|
|
54
|
-
const pathList = path.split(fp.sep);
|
|
55
|
-
while (pathList.length > 1) {
|
|
56
|
-
const testPath = fp.join(pathList.join(fp.sep), '.git');
|
|
57
|
-
try {
|
|
58
|
-
await fs.access(testPath);
|
|
59
|
-
const stat = await fs.lstat(testPath);
|
|
60
|
-
if (stat.isDirectory()) {
|
|
61
|
-
return pathList.join(fp.sep);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
// Do nothing
|
|
66
|
-
}
|
|
67
|
-
pathList.pop();
|
|
68
|
-
}
|
|
69
|
-
return null;
|
|
70
|
-
}
|
|
71
|
-
async function upsert(filePath, text) {
|
|
72
|
-
try {
|
|
73
|
-
await fs.access(filePath);
|
|
74
|
-
console.log('Found', filePath);
|
|
75
|
-
}
|
|
76
|
-
catch (error) {
|
|
77
|
-
await fs.writeFile(filePath, '#!/usr/bin/env sh' + '\n' +
|
|
78
|
-
'. "$(dirname -- "$0")/_/husky.sh"' + '\n', 'utf-8');
|
|
79
|
-
console.log('Created', filePath);
|
|
80
|
-
}
|
|
81
|
-
const fileText = await fs.readFile(filePath, 'utf-8');
|
|
82
|
-
const lines = fileText.trim().split('\n');
|
|
83
|
-
const index = lines
|
|
84
|
-
.findIndex(line => line.trim().includes(text));
|
|
85
|
-
if (index === -1) {
|
|
86
|
-
await fs.appendFile(filePath, '\n' + text + '\n', 'utf-8');
|
|
87
|
-
console.log(`Added "${text}" to ${filePath}`);
|
|
88
|
-
}
|
|
89
|
-
}
|