Skip to content

Commit 141cc66

Browse files
committed
feat(@skyroc/cli): ✨ add release scripts and changelog generation options to streamline versioning process
1 parent 6ef2aa5 commit 141cc66

File tree

8 files changed

+232
-53
lines changed

8 files changed

+232
-53
lines changed
Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,38 @@
1+
import type { VersionBumpOptions } from 'bumpp';
12
import { versionBump } from 'bumpp';
23

3-
export async function release(execute = 'npx soy changelog', push = true) {
4-
await versionBump({
4+
import type { CliOption, ReleaseOptions } from '../types';
5+
6+
export interface ArgsReleaseOptions extends ReleaseOptions {
7+
releaseOptions?: CliOption['releaseOptions'];
8+
}
9+
10+
export async function releaseArgs(agrs: ArgsReleaseOptions) {
11+
const { execute = 'npx sr changelog', packageName, preid = 'beta', push = true, release, releaseOptions } = agrs;
12+
13+
const defaultOptions = {
514
all: true,
615
commit: 'chore(projects): release v%s',
716
execute,
817
files: ['**/package.json', '!**/node_modules'],
18+
preid,
919
push,
20+
release,
1021
tag: true
11-
});
22+
};
23+
24+
const cliOptions =
25+
typeof releaseOptions === 'function'
26+
? releaseOptions({
27+
execute,
28+
packageName,
29+
preid,
30+
push,
31+
release
32+
})
33+
: releaseOptions;
34+
35+
const options = releaseOptions ? cliOptions : defaultOptions;
36+
37+
await versionBump(options as VersionBumpOptions);
1238
}

internal/cli/src/config/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ const defaultOptions: CliOption = {
2525
/^Automatic merge(.*)/,
2626
/^Auto-merged (.*?) into (.*)/
2727
],
28-
ncuCommandArgs: ['--deep', '-u']
28+
ncuCommandArgs: ['--deep', '-u'],
29+
releaseOptions: {}
2930
};
3031

3132
export async function loadCliOptions(overrides?: Partial<CliOption>, cwd = process.cwd()) {

internal/cli/src/index.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { blue, lightGreen } from 'kolorist';
33

44
import { version } from '../package.json';
55

6-
import { cleanup, genChangelog, gitCommit, gitCommitVerify, release, updatePkg } from './commands';
6+
import { cleanup, genChangelog, gitCommit, gitCommitVerify, releaseArgs, updatePkg } from './commands';
77
import { loadCliOptions } from './config';
88
import type { Lang } from './locales';
99
import type { CliOption, GitCommitScope, GitCommitType, GitEmojiItem } from './types';
@@ -33,8 +33,14 @@ interface CommandArg {
3333
* @default 'en-us'
3434
*/
3535
lang?: Lang;
36+
/** The package name to bump */
37+
packageName?: string;
38+
/** The prerelease type (e.g. "alpha", "beta", "next"). Defaults to "beta" */
39+
preid?: string;
3640
/** Indicates whether to push the git commit and tag. Defaults to true */
3741
push?: boolean;
42+
/** The release type (e.g. "conventional", "npm", "yarn", "pnpm"). Defaults to "conventional" */
43+
release?: string;
3844
/** Generate changelog by total tags */
3945
total?: boolean;
4046
}
@@ -52,12 +58,18 @@ export async function setupCli() {
5258
)
5359
.option('-p, --push', 'Indicates whether to push the git commit and tag')
5460
.option('-t, --total', 'Generate changelog by total tags')
61+
.option('-pn, --packageName <packageName>', 'The package name to bump')
5562
.option(
5663
'-c, --cleanupDir <dir>',
5764
'The glob pattern of dirs to cleanup, If not set, it will use the default value, Multiple values use "," to separate them'
5865
)
5966
.option('-l, --lang <lang>', 'display lang of cli', { default: 'en-us', type: [String] })
6067
.option('-m, --gitEmoji <emoji>', 'git commit emoji')
68+
.option('-pr, --preid <preid>', 'The prerelease type (e.g. "alpha", "beta", "next"). Defaults to "beta"')
69+
.option(
70+
'-re, --release <release>',
71+
'The release type (e.g. "conventional", "npm", "yarn", "pnpm"). Defaults to "conventional"'
72+
)
6173
.help();
6274

6375
const commands: CommandWithAction<CommandArg> = {
@@ -87,7 +99,14 @@ export async function setupCli() {
8799
},
88100
release: {
89101
action: async args => {
90-
await release(args?.execute, args?.push);
102+
await releaseArgs({
103+
execute: args?.execute,
104+
packageName: args?.packageName,
105+
preid: args?.preid,
106+
push: args?.push,
107+
release: args?.release,
108+
releaseOptions: cliOptions.releaseOptions
109+
});
91110
},
92111
desc: 'release: update version, generate changelog, commit code'
93112
},

internal/cli/src/types/index.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { ChangelogOption } from '@soybeanjs/changelog';
2+
import type { VersionBumpOptions } from 'bumpp';
23

34
/**
45
* Git commit type item [type, description]
@@ -15,6 +16,14 @@ export type GitCommitScope = readonly [scope: string, description: string];
1516
*/
1617
export type GitEmojiItem = readonly [type: string, emoji: string];
1718

19+
export type ReleaseOptions = {
20+
execute?: string;
21+
packageName?: string;
22+
preid?: string;
23+
push?: boolean;
24+
release?: string;
25+
};
26+
1827
export interface CliOption {
1928
/**
2029
* Options of generate changelog
@@ -55,4 +64,10 @@ export interface CliOption {
5564
* @default ['--deep', '-u']
5665
*/
5766
ncuCommandArgs: string[];
67+
/**
68+
* Options of bump package
69+
*
70+
* @link https://github.com/bevry/bumpp
71+
*/
72+
releaseOptions: Partial<VersionBumpOptions> | ((options: ReleaseOptions) => VersionBumpOptions);
5873
}

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
},
1010
"scripts": {
1111
"build": "turbo run build",
12+
"changelog": "sr changelog",
1213
"check-types": "turbo run check-types",
1314
"commit": "sr git-commit",
1415
"cpn": "tsx script/cp.ts",
@@ -18,7 +19,11 @@
1819
"lint": "turbo run lint",
1920
"lint:fix": "eslint . --fix",
2021
"postinstall": "tsx script/postinstall.ts",
21-
"release": "tsx script/bump.ts"
22+
"release": "tsx script/bump.ts",
23+
"release:alpha": "tsx script/release.ts --type alpha",
24+
"release:beta": "tsx script/release.ts --type beta",
25+
"release:prod": "tsx script/release.ts --type prod",
26+
"release:rc": "tsx script/release.ts --type rc"
2227
},
2328
"dependencies": {
2429
"@changesets/changelog-github": "0.5.1",

script/bump.ts

Lines changed: 0 additions & 45 deletions
This file was deleted.

script/release.ts

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { execSync } from 'node:child_process';
2+
3+
/**
4+
* Release type for different version publishing scenarios
5+
* - prod: Production release (stable version)
6+
* - beta/alpha/rc: Pre-release versions for testing
7+
*/
8+
type ReleaseType = 'alpha' | 'beta' | 'prod' | 'rc';
9+
10+
/**
11+
* Get default configuration for each release type
12+
* @param type - The release type (prod, beta, alpha, rc)
13+
* @returns Default configuration including preid and release strategy
14+
*/
15+
function getDefaultConfig(type: ReleaseType) {
16+
const configs = {
17+
alpha: { preid: 'alpha', release: 'prerelease' },
18+
beta: { preid: 'beta', release: 'prerelease' },
19+
prod: { preid: undefined, release: 'patch' },
20+
rc: { preid: 'rc', release: 'prerelease' }
21+
};
22+
23+
return configs[type];
24+
}
25+
26+
/**
27+
* Parse command line arguments
28+
* @returns Parsed arguments as key-value pairs
29+
*/
30+
function parseArgs() {
31+
const args = process.argv.slice(2);
32+
const result: Record<string, string | undefined> = {
33+
push: 'true'
34+
};
35+
36+
for (let i = 0; i < args.length; i += 1) {
37+
const arg = args[i];
38+
if ((arg === '--type' || arg === '-t') && args[i + 1]) {
39+
result.type = args[i + 1];
40+
i += 1;
41+
} else if ((arg === '--path' || arg === '--packageName' || arg === '-p') && args[i + 1]) {
42+
result.packageName = args[i + 1];
43+
i += 1;
44+
} else if ((arg === '--release' || arg === '-r') && args[i + 1]) {
45+
result.release = args[i + 1];
46+
i += 1;
47+
} else if ((arg === '--preid' || arg === '-pr') && args[i + 1]) {
48+
result.preid = args[i + 1];
49+
i += 1;
50+
} else if (arg === '--push' && args[i + 1]) {
51+
result.push = args[i + 1];
52+
i += 1;
53+
} else if (arg === '--no-push') {
54+
result.push = 'false';
55+
}
56+
}
57+
58+
return result;
59+
}
60+
61+
const options = parseArgs();
62+
63+
// Validate type parameter - must be one of: prod, beta, alpha, rc
64+
if (!options.type || !['prod', 'beta', 'alpha', 'rc'].includes(options.type)) {
65+
// eslint-disable-next-line no-console
66+
console.error('❌ Release type is required: --type prod|beta|alpha|rc');
67+
process.exit(1);
68+
}
69+
70+
const type = options.type as ReleaseType;
71+
const defaultConfig = getDefaultConfig(type);
72+
73+
// Build the command with appropriate arguments
74+
const cmdParts = ['sr', 'release'];
75+
76+
if (options.packageName) {
77+
cmdParts.push('--packageName', options.packageName);
78+
}
79+
80+
// Use user-specified parameters if provided, otherwise use default values
81+
const release = options.release || defaultConfig.release;
82+
cmdParts.push('--release', release);
83+
84+
// Only pre-release versions need preid (beta, alpha, rc)
85+
const preid = options.preid || defaultConfig.preid;
86+
if (preid) {
87+
cmdParts.push('--preid', preid);
88+
}
89+
90+
if (options.push === 'true') {
91+
cmdParts.push('--push');
92+
}
93+
94+
const cmd = cmdParts.join(' ');
95+
96+
// eslint-disable-next-line no-console
97+
console.log(`🚀 Executing command: ${cmd}`);
98+
99+
execSync(cmd, {
100+
stdio: 'inherit'
101+
});

skyroc.config.ts

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1+
import { execSync } from 'node:child_process';
2+
import fs from 'node:fs';
3+
import path from 'node:path';
4+
15
import { defineConfig } from '@skyroc/cli';
26

7+
let tag = '';
8+
39
export default defineConfig({
10+
changelogOptions: {
11+
to: tag
12+
},
413
// Custom git commit scopes
514
// If not set, will use default scopes from locale
615
gitCommitScopes: [
@@ -19,5 +28,53 @@ export default defineConfig({
1928
['@skyroc/cli', 'CLI for skyroc-ui'],
2029
['skyroc-ui-docs', 'Docs for skyroc-ui'],
2130
['other', 'other changes']
22-
]
31+
],
32+
releaseOptions: options => {
33+
const { packageName: pathName, preid, release } = options;
34+
35+
// Validate package name is provided
36+
if (!pathName) {
37+
// eslint-disable-next-line no-console
38+
console.error('❌ Package name is required, e.g.: pnpm release skyroc-form');
39+
process.exit(1);
40+
}
41+
const cwd = path.resolve(pathName);
42+
const pkgPath = path.join(cwd, 'package.json');
43+
if (!fs.existsSync(pkgPath)) {
44+
// eslint-disable-next-line no-console
45+
console.error(`❌ Package not found: ${pkgPath}`);
46+
process.exit(1);
47+
}
48+
49+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
50+
51+
const current = pkg.version;
52+
53+
const pkgName = pkg.name;
54+
55+
console.log(`🔍 Current version: ${pkgName}@${current}`);
56+
57+
return {
58+
commit: `chore(${pkgName}): release v%s`,
59+
confirm: false,
60+
cwd,
61+
execute: op => {
62+
console.log('New version:', op.state.newVersion);
63+
64+
tag = `${pkgName}@${op.state.newVersion}`;
65+
execSync(`npx sr changelog`);
66+
},
67+
files: ['package.json'],
68+
preid,
69+
progress(info) {
70+
// Log release progress events
71+
72+
console.log(`[${info.event}] ${info.newVersion ?? ''} ${info.commit ?? ''}`);
73+
},
74+
// Automatic commit type analysis
75+
push: false,
76+
release,
77+
tag: `${pkgName}@%s`
78+
};
79+
}
2380
});

0 commit comments

Comments
 (0)