@logickernel/agileflow 0.1.0 → 0.2.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/docs/README.md +0 -1
- package/docs/cli-reference.md +231 -60
- package/docs/getting-started.md +144 -160
- package/package.json +1 -1
- package/src/git-push.js +26 -0
- package/src/github-push.js +156 -0
- package/src/gitlab-push.js +136 -0
- package/src/index.js +93 -29
- package/src/utils.js +117 -104
- package/docs/gitlab-ci-template.md +0 -324
- package/src/git-utils.js +0 -57
- package/src/local.js +0 -17
- package/templates/agileflow-tagged.gitlab-ci.yml +0 -66
- package/templates/agileflow.gitlab-ci.yml +0 -64
package/src/index.js
CHANGED
|
@@ -1,50 +1,114 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { version } = require('../package.json');
|
|
4
|
+
const { processVersionInfo } = require('./utils');
|
|
4
5
|
|
|
5
6
|
function printHelp() {
|
|
6
|
-
console.log(`agileflow - Automatic semantic versioning and changelog generation
|
|
7
|
+
console.log(`agileflow - Automatic semantic versioning and changelog generation tool.
|
|
7
8
|
|
|
8
9
|
Usage:
|
|
9
10
|
agileflow [options]
|
|
10
11
|
agileflow <command>
|
|
11
12
|
|
|
12
13
|
Commands:
|
|
13
|
-
|
|
14
|
+
<none> Prints the current version, next version, commits, and changelog
|
|
15
|
+
push Push a semantic version tag to the remote repository (native git)
|
|
16
|
+
gitlab Push a semantic version tag via GitLab API (for GitLab CI)
|
|
17
|
+
github Push a semantic version tag via GitHub API (for GitHub Actions)
|
|
14
18
|
|
|
15
19
|
Options:
|
|
16
|
-
--
|
|
17
|
-
-h, --help
|
|
18
|
-
-v, --version
|
|
20
|
+
--quiet Only output the next version (or empty if no bump)
|
|
21
|
+
-h, --help Show this help message
|
|
22
|
+
-v, --version Show version number
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
agileflow # Run on main branch
|
|
22
|
-
agileflow --branch develop # Run on develop branch
|
|
23
|
-
agileflow gitlab-ci
|
|
24
|
-
|
|
25
|
-
For more information, visit: https://code.logickernel.com/kernel/agileflow
|
|
24
|
+
For more information, visit: https://code.logickernel.com/tools/agileflow
|
|
26
25
|
`);
|
|
27
26
|
}
|
|
28
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Parses command line arguments.
|
|
30
|
+
* @param {Array<string>} args - Command line arguments
|
|
31
|
+
* @returns {{quiet: boolean}}
|
|
32
|
+
*/
|
|
29
33
|
function parseArgs(args) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
return {
|
|
35
|
+
quiet: args.includes('--quiet'),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Displays version info to the console.
|
|
41
|
+
* @param {{currentVersion: string|null, nextVersion: string|null, commits: Array, changelog: string}} info
|
|
42
|
+
* @param {boolean} quiet - Only output the next version
|
|
43
|
+
*/
|
|
44
|
+
function displayVersionInfo(info, quiet) {
|
|
45
|
+
const { currentVersion, nextVersion, commits, changelog } = info;
|
|
46
|
+
|
|
47
|
+
if (quiet) {
|
|
48
|
+
if (nextVersion) {
|
|
49
|
+
console.log(nextVersion);
|
|
35
50
|
}
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
console.log(`Current version: ${currentVersion || 'none'}`);
|
|
55
|
+
console.log(`Next version: ${nextVersion || 'no bump needed'}`);
|
|
56
|
+
console.log(`Commits since current version: ${commits.length}`);
|
|
57
|
+
if (changelog) {
|
|
58
|
+
console.log(`\nChangelog:\n${changelog}`);
|
|
36
59
|
}
|
|
37
|
-
return parsed;
|
|
38
60
|
}
|
|
39
61
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Handles a push command.
|
|
64
|
+
* @param {string} pushType - 'push', 'gitlab', or 'github'
|
|
65
|
+
* @param {{quiet: boolean}} options
|
|
66
|
+
*/
|
|
67
|
+
async function handlePushCommand(pushType, options) {
|
|
68
|
+
const info = await processVersionInfo();
|
|
69
|
+
|
|
70
|
+
// Display version info
|
|
71
|
+
displayVersionInfo(info, options.quiet);
|
|
72
|
+
|
|
73
|
+
// Skip push if no version bump needed
|
|
74
|
+
if (!info.nextVersion) {
|
|
75
|
+
if (!options.quiet) {
|
|
76
|
+
console.log('\nNo version bump needed. Skipping tag creation.');
|
|
77
|
+
}
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Get the appropriate push module
|
|
82
|
+
let pushModule;
|
|
83
|
+
switch (pushType) {
|
|
84
|
+
case 'push':
|
|
85
|
+
pushModule = require('./git-push');
|
|
86
|
+
break;
|
|
87
|
+
case 'gitlab':
|
|
88
|
+
pushModule = require('./gitlab-push');
|
|
89
|
+
break;
|
|
90
|
+
case 'github':
|
|
91
|
+
pushModule = require('./github-push');
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Create tag message from changelog
|
|
96
|
+
const tagMessage = info.changelog || info.nextVersion;
|
|
97
|
+
|
|
98
|
+
if (!options.quiet) {
|
|
99
|
+
console.log(`\nCreating tag ${info.nextVersion}...`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
await pushModule.pushTag(info.nextVersion, tagMessage);
|
|
103
|
+
|
|
104
|
+
if (!options.quiet) {
|
|
105
|
+
console.log(`Tag ${info.nextVersion} created and pushed successfully.`);
|
|
106
|
+
}
|
|
44
107
|
}
|
|
45
108
|
|
|
46
109
|
async function main() {
|
|
47
110
|
const [, , cmd, ...rest] = process.argv;
|
|
111
|
+
const options = parseArgs(cmd ? [cmd, ...rest] : rest);
|
|
48
112
|
|
|
49
113
|
// Handle help
|
|
50
114
|
if (cmd === '-h' || cmd === '--help' || cmd === 'help') {
|
|
@@ -58,14 +122,13 @@ async function main() {
|
|
|
58
122
|
process.exit(0);
|
|
59
123
|
}
|
|
60
124
|
|
|
61
|
-
// Handle
|
|
62
|
-
if (cmd === 'gitlab
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
process.exit(1);
|
|
125
|
+
// Handle push commands
|
|
126
|
+
if (cmd === 'push' || cmd === 'gitlab' || cmd === 'github') {
|
|
127
|
+
await handlePushCommand(cmd, options);
|
|
128
|
+
return;
|
|
66
129
|
}
|
|
67
130
|
|
|
68
|
-
// Unknown command
|
|
131
|
+
// Unknown command (not an option)
|
|
69
132
|
if (cmd && !cmd.startsWith('--')) {
|
|
70
133
|
console.error(`Error: Unknown command "${cmd}"`);
|
|
71
134
|
console.error();
|
|
@@ -73,8 +136,9 @@ async function main() {
|
|
|
73
136
|
process.exit(1);
|
|
74
137
|
}
|
|
75
138
|
|
|
76
|
-
// Default:
|
|
77
|
-
|
|
139
|
+
// Default: show version info
|
|
140
|
+
const info = await processVersionInfo();
|
|
141
|
+
displayVersionInfo(info, options.quiet);
|
|
78
142
|
}
|
|
79
143
|
|
|
80
144
|
process.on('unhandledRejection', (err) => {
|
package/src/utils.js
CHANGED
|
@@ -1,6 +1,66 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Executes a shell command and returns the output.
|
|
8
|
+
* @param {string} command - The command to execute
|
|
9
|
+
* @param {Object} options - Execution options
|
|
10
|
+
* @returns {string} Command output
|
|
11
|
+
* @throws {Error} If command fails
|
|
12
|
+
*/
|
|
13
|
+
function runWithOutput(command, options = {}) {
|
|
14
|
+
try {
|
|
15
|
+
return execSync(command, { stdio: 'pipe', encoding: 'utf8', ...options });
|
|
16
|
+
} catch (error) {
|
|
17
|
+
const captured = {
|
|
18
|
+
stdout: error?.stdout ? String(error.stdout) : '',
|
|
19
|
+
stderr: error?.stderr ? String(error.stderr) : '',
|
|
20
|
+
message: error?.message || 'Command failed',
|
|
21
|
+
status: typeof error?.status === 'number' ? error.status : 1,
|
|
22
|
+
};
|
|
23
|
+
try {
|
|
24
|
+
Object.defineProperty(error, '_captured', { value: captured });
|
|
25
|
+
} catch {
|
|
26
|
+
error._captured = captured;
|
|
27
|
+
}
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Executes a shell command without returning output.
|
|
34
|
+
* @param {string} command - The command to execute
|
|
35
|
+
* @param {Object} options - Execution options
|
|
36
|
+
* @throws {Error} If command fails
|
|
37
|
+
*/
|
|
38
|
+
function run(command, options = {}) {
|
|
39
|
+
execSync(command, { stdio: 'pipe', ...options });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Ensures the current directory is a git repository.
|
|
44
|
+
* @throws {Error} If the current directory is not a git repository
|
|
45
|
+
*/
|
|
46
|
+
function ensureGitRepo() {
|
|
47
|
+
if (!fs.existsSync('.git')) {
|
|
48
|
+
throw new Error('Current directory is not a git repository (missing .git directory).');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Gets the current branch name.
|
|
54
|
+
* @returns {string} Current branch name
|
|
55
|
+
* @throws {Error} If in detached HEAD state
|
|
56
|
+
*/
|
|
57
|
+
function getCurrentBranch() {
|
|
58
|
+
const branch = runWithOutput('git branch --show-current').trim();
|
|
59
|
+
if (!branch) {
|
|
60
|
+
throw new Error('Repository is in a detached HEAD state. Please check out a branch and try again.');
|
|
61
|
+
}
|
|
62
|
+
return branch;
|
|
63
|
+
}
|
|
4
64
|
|
|
5
65
|
// Conventional commit type configuration
|
|
6
66
|
const TYPE_ORDER = ['feat', 'fix', 'perf', 'refactor', 'style', 'test', 'docs', 'build', 'ci', 'chore', 'revert'];
|
|
@@ -9,15 +69,12 @@ const SEMVER_PATTERN = /^v(\d+)\.(\d+)\.(\d+)(-[a-zA-Z0-9.-]+)?$/;
|
|
|
9
69
|
|
|
10
70
|
/**
|
|
11
71
|
* Fetches tags from remote (non-destructive) if a remote is configured.
|
|
12
|
-
* This is a safe operation that doesn't modify the working directory.
|
|
13
72
|
* @returns {boolean} True if tags were fetched, false if using local tags only
|
|
14
73
|
*/
|
|
15
|
-
function
|
|
74
|
+
function fetchTags() {
|
|
16
75
|
try {
|
|
17
76
|
const remotes = runWithOutput('git remote').trim();
|
|
18
|
-
if (!remotes)
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
77
|
+
if (!remotes) return false;
|
|
21
78
|
runWithOutput('git fetch --tags --prune --prune-tags');
|
|
22
79
|
return true;
|
|
23
80
|
} catch {
|
|
@@ -25,21 +82,6 @@ function fetchTagsLocally() {
|
|
|
25
82
|
}
|
|
26
83
|
}
|
|
27
84
|
|
|
28
|
-
/**
|
|
29
|
-
* Validates that the current branch is the expected name.
|
|
30
|
-
* @param {string} expectedName - The expected name of the branch
|
|
31
|
-
* @throws {Error} If the current branch is not the expected name or in detached HEAD state
|
|
32
|
-
*/
|
|
33
|
-
function validateBranchName(expectedName) {
|
|
34
|
-
const branch = runWithOutput('git branch --show-current').trim();
|
|
35
|
-
if (!branch) {
|
|
36
|
-
throw new Error('Repository is in a detached HEAD state. Please check out a branch and try again.');
|
|
37
|
-
}
|
|
38
|
-
if (branch !== expectedName) {
|
|
39
|
-
throw new Error(`Current branch is "${branch}", not "${expectedName}". Switch to ${expectedName} or use --branch ${branch}.`);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
85
|
/**
|
|
44
86
|
* Gets all tags pointing to a specific commit.
|
|
45
87
|
* @param {string} commitSha - The commit SHA to check for tags
|
|
@@ -57,18 +99,13 @@ function getTagsForCommit(commitSha) {
|
|
|
57
99
|
/**
|
|
58
100
|
* Parses a conventional commit message.
|
|
59
101
|
* @param {string} message - The commit message to parse
|
|
60
|
-
* @returns {{type: string, breaking: boolean, scope: string, description: string}|null}
|
|
102
|
+
* @returns {{type: string, breaking: boolean, scope: string, description: string}|null}
|
|
61
103
|
*/
|
|
62
104
|
function parseConventionalCommit(message) {
|
|
63
105
|
if (!message) return null;
|
|
64
|
-
|
|
65
|
-
// Get the first line (subject) of the commit message
|
|
66
106
|
const subject = message.split('\n')[0].trim();
|
|
67
|
-
|
|
68
|
-
// Conventional commit pattern: type[!]?(scope)?: description
|
|
69
107
|
const match = subject.match(/^(\w+)(!)?(?:\(([^)]+)\))?:\s+(.+)$/);
|
|
70
108
|
if (!match) return null;
|
|
71
|
-
|
|
72
109
|
return {
|
|
73
110
|
type: match[1].toLowerCase(),
|
|
74
111
|
breaking: Boolean(match[2]),
|
|
@@ -79,17 +116,14 @@ function parseConventionalCommit(message) {
|
|
|
79
116
|
|
|
80
117
|
/**
|
|
81
118
|
* Expands commit information by finding the latest version and filtering commits.
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* @param {Array<{hash: string, datetime: string, author: string, message: string, tags: Array<string>}>} commits - Array of commit objects
|
|
85
|
-
* @returns {{latestVersion: string|null, commits: Array}} Object with latestVersion and filtered commits array
|
|
119
|
+
* @param {Array} commits - Array of commit objects (newest to oldest)
|
|
120
|
+
* @returns {{latestVersion: string|null, commits: Array}} Filtered commits since last version
|
|
86
121
|
*/
|
|
87
122
|
function expandCommitInfo(commits) {
|
|
88
123
|
if (!commits?.length) {
|
|
89
124
|
return { latestVersion: null, commits: [] };
|
|
90
125
|
}
|
|
91
126
|
|
|
92
|
-
// Find the first commit (newest) that has a semver tag
|
|
93
127
|
const taggedIndex = commits.findIndex(commit =>
|
|
94
128
|
commit.tags?.some(tag => SEMVER_PATTERN.test(tag))
|
|
95
129
|
);
|
|
@@ -99,16 +133,17 @@ function expandCommitInfo(commits) {
|
|
|
99
133
|
}
|
|
100
134
|
|
|
101
135
|
const latestVersion = commits[taggedIndex].tags.find(tag => SEMVER_PATTERN.test(tag));
|
|
136
|
+
// Exclude the tagged commit itself - only return commits since the tag
|
|
102
137
|
return {
|
|
103
138
|
latestVersion,
|
|
104
|
-
commits: commits.slice(0, taggedIndex
|
|
139
|
+
commits: commits.slice(0, taggedIndex),
|
|
105
140
|
};
|
|
106
141
|
}
|
|
107
142
|
|
|
108
143
|
/**
|
|
109
|
-
* Extracts issue reference from commit message
|
|
144
|
+
* Extracts issue reference from commit message.
|
|
110
145
|
* @param {string} message - The commit message
|
|
111
|
-
* @returns {string|null} Issue reference like "(#123)" or null
|
|
146
|
+
* @returns {string|null} Issue reference like "(#123)" or null
|
|
112
147
|
*/
|
|
113
148
|
function extractIssueReference(message) {
|
|
114
149
|
const match = message?.match(/\(?#(\d+)\)?/);
|
|
@@ -116,33 +151,26 @@ function extractIssueReference(message) {
|
|
|
116
151
|
}
|
|
117
152
|
|
|
118
153
|
/**
|
|
119
|
-
* Formats
|
|
120
|
-
* @param {string} subject -
|
|
154
|
+
* Formats commit description for changelog.
|
|
155
|
+
* @param {string} subject - First line of commit message
|
|
121
156
|
* @param {Object} parsed - Parsed conventional commit info
|
|
122
|
-
* @param {string} fullMessage - Full commit message
|
|
157
|
+
* @param {string} fullMessage - Full commit message
|
|
123
158
|
* @returns {string} Formatted description
|
|
124
159
|
*/
|
|
125
160
|
function formatChangelogDescription(subject, parsed, fullMessage) {
|
|
126
|
-
if (!parsed)
|
|
127
|
-
// Not a conventional commit, use subject as-is
|
|
128
|
-
return subject;
|
|
129
|
-
}
|
|
130
|
-
|
|
161
|
+
if (!parsed) return subject;
|
|
131
162
|
let description = parsed.description;
|
|
132
|
-
|
|
133
|
-
// Add BREAKING prefix if it's a breaking change (check both ! and BREAKING CHANGE:)
|
|
134
163
|
const isBreaking = parsed.breaking || /BREAKING CHANGE:/i.test(fullMessage);
|
|
135
164
|
if (isBreaking) {
|
|
136
165
|
description = `BREAKING: ${description}`;
|
|
137
166
|
}
|
|
138
|
-
|
|
139
167
|
return description;
|
|
140
168
|
}
|
|
141
169
|
|
|
142
170
|
/**
|
|
143
|
-
* Parses a semver version string into
|
|
144
|
-
* @param {string|null} version - Version string like "v1.2.3"
|
|
145
|
-
* @returns {{major: number, minor: number, patch: number}}
|
|
171
|
+
* Parses a semver version string into components.
|
|
172
|
+
* @param {string|null} version - Version string like "v1.2.3"
|
|
173
|
+
* @returns {{major: number, minor: number, patch: number}}
|
|
146
174
|
*/
|
|
147
175
|
function parseVersion(version) {
|
|
148
176
|
if (!version) return { major: 0, minor: 0, patch: 0 };
|
|
@@ -152,14 +180,13 @@ function parseVersion(version) {
|
|
|
152
180
|
}
|
|
153
181
|
|
|
154
182
|
/**
|
|
155
|
-
* Determines
|
|
156
|
-
* @param {{hasBreaking: boolean, hasFeat: boolean, hasPatchTypes: boolean}} analysis
|
|
183
|
+
* Determines version bump type based on commit analysis.
|
|
184
|
+
* @param {{hasBreaking: boolean, hasFeat: boolean, hasPatchTypes: boolean}} analysis
|
|
157
185
|
* @param {boolean} isPreOneZero - Whether current version is 0.x.x
|
|
158
|
-
* @returns {'major'|'minor'|'patch'|'none'}
|
|
186
|
+
* @returns {'major'|'minor'|'patch'|'none'}
|
|
159
187
|
*/
|
|
160
188
|
function determineVersionBumpType(analysis, isPreOneZero) {
|
|
161
189
|
const { hasBreaking, hasFeat, hasPatchTypes } = analysis;
|
|
162
|
-
|
|
163
190
|
if (isPreOneZero) {
|
|
164
191
|
if (hasBreaking || hasFeat) return 'minor';
|
|
165
192
|
if (hasPatchTypes) return 'patch';
|
|
@@ -173,17 +200,17 @@ function determineVersionBumpType(analysis, isPreOneZero) {
|
|
|
173
200
|
|
|
174
201
|
/**
|
|
175
202
|
* Applies a version bump to the current version.
|
|
176
|
-
* @param {{major: number, minor: number, patch: number}} current
|
|
177
|
-
* @param {'major'|'minor'|'patch'|'none'} bump
|
|
178
|
-
* @returns {string} Next version string
|
|
203
|
+
* @param {{major: number, minor: number, patch: number}} current
|
|
204
|
+
* @param {'major'|'minor'|'patch'|'none'} bump
|
|
205
|
+
* @returns {string|null} Next version string or null if no bump
|
|
179
206
|
*/
|
|
180
207
|
function applyVersionBump(current, bump) {
|
|
181
|
-
|
|
208
|
+
const { major, minor, patch } = current;
|
|
182
209
|
switch (bump) {
|
|
183
210
|
case 'major': return `v${major + 1}.0.0`;
|
|
184
211
|
case 'minor': return `v${major}.${minor + 1}.0`;
|
|
185
212
|
case 'patch': return `v${major}.${minor}.${patch + 1}`;
|
|
186
|
-
default: return
|
|
213
|
+
default: return null;
|
|
187
214
|
}
|
|
188
215
|
}
|
|
189
216
|
|
|
@@ -255,9 +282,9 @@ function generateTypeChangelog(commits) {
|
|
|
255
282
|
}
|
|
256
283
|
|
|
257
284
|
/**
|
|
258
|
-
* Calculates the next version and generates a changelog
|
|
259
|
-
* @param {{latestVersion: string|null, commits: Array}} expandedInfo
|
|
260
|
-
* @returns {{nextVersion: string, changelog: string}}
|
|
285
|
+
* Calculates the next version and generates a changelog.
|
|
286
|
+
* @param {{latestVersion: string|null, commits: Array}} expandedInfo
|
|
287
|
+
* @returns {{nextVersion: string|null, changelog: string}}
|
|
261
288
|
*/
|
|
262
289
|
function calculateNextVersionAndChangelog(expandedInfo) {
|
|
263
290
|
const { latestVersion, commits } = expandedInfo;
|
|
@@ -278,7 +305,6 @@ function calculateNextVersionAndChangelog(expandedInfo) {
|
|
|
278
305
|
changelogLines.push('');
|
|
279
306
|
}
|
|
280
307
|
|
|
281
|
-
// Remove trailing empty line
|
|
282
308
|
if (changelogLines.at(-1) === '') {
|
|
283
309
|
changelogLines.pop();
|
|
284
310
|
}
|
|
@@ -287,54 +313,18 @@ function calculateNextVersionAndChangelog(expandedInfo) {
|
|
|
287
313
|
}
|
|
288
314
|
|
|
289
315
|
/**
|
|
290
|
-
*
|
|
291
|
-
* @param {string} branch - The branch to process
|
|
292
|
-
* @returns {Promise<{previousVersion: string|null, nextVersion: string, commits: Array, conventionalCommits: Object, changelog: string}>} Promise resolving to version info
|
|
293
|
-
*/
|
|
294
|
-
async function processVersionInfo(branch) {
|
|
295
|
-
ensureGitRepo();
|
|
296
|
-
validateBranchName(branch);
|
|
297
|
-
fetchTagsLocally();
|
|
298
|
-
|
|
299
|
-
const allCommits = getAllBranchCommits(branch);
|
|
300
|
-
const expandedInfo = expandCommitInfo(allCommits);
|
|
301
|
-
const { latestVersion, commits } = expandedInfo;
|
|
302
|
-
|
|
303
|
-
// Group commits by conventional type
|
|
304
|
-
const conventionalCommits = Object.fromEntries(TYPE_ORDER.map(t => [t, []]));
|
|
305
|
-
for (const commit of commits) {
|
|
306
|
-
const parsed = parseConventionalCommit(commit.message);
|
|
307
|
-
if (parsed && conventionalCommits[parsed.type]) {
|
|
308
|
-
conventionalCommits[parsed.type].push({ ...commit, conventional: parsed });
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
const { nextVersion, changelog } = calculateNextVersionAndChangelog(expandedInfo);
|
|
313
|
-
|
|
314
|
-
return {
|
|
315
|
-
previousVersion: latestVersion,
|
|
316
|
-
nextVersion,
|
|
317
|
-
commits,
|
|
318
|
-
conventionalCommits,
|
|
319
|
-
changelog,
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* Retrieves all commits in the history of the specified branch, including merged commits.
|
|
325
|
-
* Returns a simplified array with commit hash, datetime, author, commit message, and tags.
|
|
316
|
+
* Retrieves all commits in the history of the specified branch.
|
|
326
317
|
* @param {string} branch - The branch to get commits from
|
|
327
|
-
* @returns {Array<{hash: string, datetime: string, author: string, message: string, tags: Array<string>}>}
|
|
318
|
+
* @returns {Array<{hash: string, datetime: string, author: string, message: string, tags: Array<string>}>}
|
|
328
319
|
*/
|
|
329
320
|
function getAllBranchCommits(branch) {
|
|
330
321
|
try {
|
|
331
|
-
// Verify the branch exists
|
|
332
322
|
runWithOutput(`git rev-parse --verify ${branch}`);
|
|
333
323
|
} catch {
|
|
334
324
|
return [];
|
|
335
325
|
}
|
|
336
326
|
|
|
337
|
-
const RS = '\x1E';
|
|
327
|
+
const RS = '\x1E';
|
|
338
328
|
const COMMIT_SEP = `${RS}${RS}`;
|
|
339
329
|
|
|
340
330
|
try {
|
|
@@ -363,14 +353,37 @@ function getAllBranchCommits(branch) {
|
|
|
363
353
|
}
|
|
364
354
|
}
|
|
365
355
|
|
|
356
|
+
/**
|
|
357
|
+
* Processes version information for the current branch.
|
|
358
|
+
* @returns {Promise<{currentVersion: string|null, nextVersion: string|null, commits: Array, changelog: string}>}
|
|
359
|
+
*/
|
|
360
|
+
async function processVersionInfo() {
|
|
361
|
+
ensureGitRepo();
|
|
362
|
+
const branch = getCurrentBranch();
|
|
363
|
+
fetchTags();
|
|
364
|
+
|
|
365
|
+
const allCommits = getAllBranchCommits(branch);
|
|
366
|
+
const expandedInfo = expandCommitInfo(allCommits);
|
|
367
|
+
const { latestVersion, commits } = expandedInfo;
|
|
368
|
+
const { nextVersion, changelog } = calculateNextVersionAndChangelog(expandedInfo);
|
|
369
|
+
|
|
370
|
+
return {
|
|
371
|
+
currentVersion: latestVersion,
|
|
372
|
+
nextVersion,
|
|
373
|
+
commits,
|
|
374
|
+
changelog,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
|
|
366
378
|
module.exports = {
|
|
379
|
+
run,
|
|
380
|
+
runWithOutput,
|
|
367
381
|
ensureGitRepo,
|
|
368
|
-
|
|
369
|
-
|
|
382
|
+
getCurrentBranch,
|
|
383
|
+
fetchTags,
|
|
370
384
|
getAllBranchCommits,
|
|
371
385
|
expandCommitInfo,
|
|
372
386
|
calculateNextVersionAndChangelog,
|
|
373
387
|
processVersionInfo,
|
|
374
388
|
parseConventionalCommit,
|
|
375
389
|
};
|
|
376
|
-
|