fg-devkit 1.8.3 → 1.8.4
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/package.json +2 -1
- package/scripts/fg-devkit.mjs +22 -6
- package/scripts/release.sh +70 -14
- package/scripts/resolve-candidate-version.mjs +80 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fg-devkit",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.4",
|
|
4
4
|
"description": "Shared configs, scripts, and DX tooling for Vue / TypeScript frontend repos",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"./scripts/poeditor-upload.mjs": "./scripts/poeditor-upload.mjs",
|
|
46
46
|
"./scripts/scaffold-vue.mjs": "./scripts/scaffold-vue.mjs",
|
|
47
47
|
"./scripts/fg-devkit.mjs": "./scripts/fg-devkit.mjs",
|
|
48
|
+
"./scripts/resolve-candidate-version.mjs": "./scripts/resolve-candidate-version.mjs",
|
|
48
49
|
"./scripts/release.sh": "./scripts/release.sh",
|
|
49
50
|
"./scripts/cz/.cz-config.cjs": "./scripts/cz/.cz-config.cjs",
|
|
50
51
|
"./cursor-rules/core-coding-standards.mdc": "./.cursor/rules/core-coding-standards.mdc"
|
package/scripts/fg-devkit.mjs
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* pnpm exec fg-devkit setup-lefthook
|
|
21
21
|
* pnpm exec fg-devkit prune-consumer-deps [--dry-run]
|
|
22
22
|
* pnpm exec fg-devkit full-consumer-setup
|
|
23
|
-
* pnpm exec fg-devkit create-release [patch|minor|major]
|
|
23
|
+
* pnpm exec fg-devkit create-release [release|candidate] [patch|minor|major]
|
|
24
24
|
* pnpm exec fg-devkit commit [cz-args...] (czg/cz-git with fg-devkit bundled config)
|
|
25
25
|
* pnpm exec fg-devkit commit-vuln (staged package.json version bumps → vuln() commit)
|
|
26
26
|
* pnpm exec fg-devkit lint [eslint-args...] (run ESLint with fg-devkit bundled packages)
|
|
@@ -72,7 +72,7 @@ function runNode(scriptRelative, args = [], options = {}) {
|
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
74
|
* Run release.sh (pnpm version bump, git push, gh release). Uses consumer cwd.
|
|
75
|
-
*
|
|
75
|
+
* Args: [release|candidate] [patch|minor|major] or [patch|minor|major] [release|candidate].
|
|
76
76
|
*/
|
|
77
77
|
function runReleaseScript(args = []) {
|
|
78
78
|
const shPath = path.join(scriptDir, 'release.sh')
|
|
@@ -493,7 +493,8 @@ Commands:
|
|
|
493
493
|
setup-lefthook Setup lefthook and migrate from husky/lint-staged
|
|
494
494
|
prune-consumer-deps [--dry-run] Remove consumer tooling deps bundled by fg-devkit
|
|
495
495
|
full-consumer-setup Run: step 7 -> scripts -> lefthook -> step 3 -> step 2 -> pnpm install
|
|
496
|
-
create-release [
|
|
496
|
+
create-release [release|candidate] [patch|minor|major]
|
|
497
|
+
Stable release or candidate (X.Y.Z-rc.N); omit = interactive menu
|
|
497
498
|
(alias: createRelease)
|
|
498
499
|
commit [args...] czg/cz-git with fg-devkit bundled config
|
|
499
500
|
commit-vuln Commit staged dependency bumps as vuln() (alias: vuln-commit)
|
|
@@ -635,8 +636,20 @@ async function runInteractiveMenu() {
|
|
|
635
636
|
}
|
|
636
637
|
|
|
637
638
|
if (group === 'release') {
|
|
638
|
-
const
|
|
639
|
+
const releaseKind = await selectPrompt({
|
|
639
640
|
message: 'Create release',
|
|
641
|
+
choices: [
|
|
642
|
+
{ name: 'Release', value: 'release' },
|
|
643
|
+
{ name: 'Candidate', value: 'candidate' },
|
|
644
|
+
{ name: 'Cancel', value: 'cancel' },
|
|
645
|
+
],
|
|
646
|
+
default: 'release',
|
|
647
|
+
loop: false,
|
|
648
|
+
})
|
|
649
|
+
if (releaseKind === 'cancel') continue
|
|
650
|
+
|
|
651
|
+
const bumpChoice = await selectPrompt({
|
|
652
|
+
message: releaseKind === 'candidate' ? 'Candidate' : 'Release',
|
|
640
653
|
choices: [
|
|
641
654
|
{ name: 'Patch', value: 'patch' },
|
|
642
655
|
{ name: 'Minor', value: 'minor' },
|
|
@@ -646,8 +659,11 @@ async function runInteractiveMenu() {
|
|
|
646
659
|
default: 'patch',
|
|
647
660
|
loop: false,
|
|
648
661
|
})
|
|
649
|
-
if (
|
|
650
|
-
|
|
662
|
+
if (bumpChoice === 'cancel') continue
|
|
663
|
+
|
|
664
|
+
const releaseArgs =
|
|
665
|
+
releaseKind === 'candidate' ? [bumpChoice, 'candidate'] : [bumpChoice]
|
|
666
|
+
return runSelectedAction(() => runReleaseScript(releaseArgs))
|
|
651
667
|
}
|
|
652
668
|
|
|
653
669
|
if (group === 'lint-typecheck') {
|
package/scripts/release.sh
CHANGED
|
@@ -3,12 +3,29 @@
|
|
|
3
3
|
# Interactive or scripted release for this package: bumps version with pnpm, pushes commits/tags,
|
|
4
4
|
# and creates a GitHub Release with generated notes (requires gh CLI, authenticated).
|
|
5
5
|
#
|
|
6
|
-
# Usage:
|
|
7
|
-
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# ./scripts/release.sh [patch|minor|major] # stable release (default mode)
|
|
8
|
+
# ./scripts/release.sh [patch|minor|major] candidate # prerelease tag X.Y.Z-rc.N
|
|
9
|
+
# ./scripts/release.sh candidate [patch|minor|major]
|
|
10
|
+
#
|
|
11
|
+
# Candidate tags follow SemVer prerelease format: <version>-rc.<number> (e.g. 2.8.0-rc.1).
|
|
8
12
|
|
|
9
13
|
set -euo pipefail
|
|
10
14
|
|
|
11
|
-
bump_type="
|
|
15
|
+
bump_type=""
|
|
16
|
+
release_mode="release"
|
|
17
|
+
|
|
18
|
+
for arg in "$@"; do
|
|
19
|
+
case "$arg" in
|
|
20
|
+
patch | minor | major) bump_type="$arg" ;;
|
|
21
|
+
release | candidate) release_mode="$arg" ;;
|
|
22
|
+
*)
|
|
23
|
+
echo "Unknown argument: $arg"
|
|
24
|
+
echo "Usage: ./scripts/release.sh [patch|minor|major] [release|candidate]"
|
|
25
|
+
exit 1
|
|
26
|
+
;;
|
|
27
|
+
esac
|
|
28
|
+
done
|
|
12
29
|
|
|
13
30
|
if [[ -z "$bump_type" ]]; then
|
|
14
31
|
echo "Select release type:"
|
|
@@ -29,7 +46,7 @@ if [[ -z "$bump_type" ]]; then
|
|
|
29
46
|
fi
|
|
30
47
|
|
|
31
48
|
if [[ "$bump_type" != "major" && "$bump_type" != "minor" && "$bump_type" != "patch" ]]; then
|
|
32
|
-
echo "Usage: ./scripts/release.sh [
|
|
49
|
+
echo "Usage: ./scripts/release.sh [patch|minor|major] [release|candidate]"
|
|
33
50
|
exit 1
|
|
34
51
|
fi
|
|
35
52
|
|
|
@@ -50,22 +67,61 @@ fi
|
|
|
50
67
|
|
|
51
68
|
previous_tag="$(git describe --tags --abbrev=0 2>/dev/null || true)"
|
|
52
69
|
|
|
53
|
-
pnpm version "$bump_type" --no-git-tag-version
|
|
54
|
-
|
|
55
|
-
new_version="$(node -p "require('./package.json').version")"
|
|
56
|
-
new_tag="v${new_version}"
|
|
57
|
-
|
|
58
70
|
is_fg_devkit_repo="$(
|
|
59
71
|
node -e "const fs=require('fs'); try { const p=JSON.parse(fs.readFileSync('./package.json','utf8')); process.stdout.write(p.name==='fg-devkit' ? 'yes' : 'no'); } catch { process.stdout.write('no'); }"
|
|
60
72
|
)"
|
|
61
73
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
74
|
+
sync_fg_devkit_package_files() {
|
|
75
|
+
if [[ "$is_fg_devkit_repo" == "yes" && -f "./scripts/sync-scaffold-vue-deps.mjs" && -f "./scaffold/vue/package.json" ]]; then
|
|
76
|
+
node ./scripts/sync-scaffold-vue-deps.mjs
|
|
77
|
+
git add package.json scaffold/vue/package.json
|
|
78
|
+
else
|
|
79
|
+
git add package.json
|
|
80
|
+
fi
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if [[ "$release_mode" == "candidate" ]]; then
|
|
84
|
+
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
85
|
+
new_version="$(node "${script_dir}/resolve-candidate-version.mjs" "$bump_type")"
|
|
86
|
+
|
|
87
|
+
node -e "
|
|
88
|
+
const fs = require('fs');
|
|
89
|
+
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
|
90
|
+
pkg.version = process.argv[1];
|
|
91
|
+
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
|
|
92
|
+
" "$new_version"
|
|
93
|
+
|
|
94
|
+
sync_fg_devkit_package_files
|
|
95
|
+
|
|
96
|
+
new_tag="v${new_version}"
|
|
97
|
+
git commit -m "${new_tag}"
|
|
98
|
+
git tag "${new_tag}"
|
|
99
|
+
|
|
100
|
+
git push
|
|
101
|
+
git push --tags
|
|
102
|
+
|
|
103
|
+
if [[ -n "$previous_tag" ]]; then
|
|
104
|
+
gh release create "$new_tag" \
|
|
105
|
+
--prerelease \
|
|
106
|
+
--generate-notes \
|
|
107
|
+
--notes-start-tag "$previous_tag"
|
|
108
|
+
else
|
|
109
|
+
gh release create "$new_tag" \
|
|
110
|
+
--prerelease \
|
|
111
|
+
--generate-notes
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
echo "Candidate release created: ${new_tag}"
|
|
115
|
+
exit 0
|
|
67
116
|
fi
|
|
68
117
|
|
|
118
|
+
pnpm version "$bump_type" --no-git-tag-version
|
|
119
|
+
|
|
120
|
+
new_version="$(node -p "require('./package.json').version")"
|
|
121
|
+
new_tag="v${new_version}"
|
|
122
|
+
|
|
123
|
+
sync_fg_devkit_package_files
|
|
124
|
+
|
|
69
125
|
git commit -m "${new_tag}"
|
|
70
126
|
git tag "${new_tag}"
|
|
71
127
|
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Resolves next candidate version: <semver>-rc.<n> (e.g. 2.8.0-rc.2).
|
|
4
|
+
* Usage: node resolve-candidate-version.mjs <patch|minor|major>
|
|
5
|
+
*/
|
|
6
|
+
import fs from 'node:fs'
|
|
7
|
+
import { execSync } from 'node:child_process'
|
|
8
|
+
|
|
9
|
+
const bump = process.argv[2]
|
|
10
|
+
if (bump !== 'patch' && bump !== 'minor' && bump !== 'major') {
|
|
11
|
+
console.error('[resolve-candidate-version] Usage: node resolve-candidate-version.mjs <patch|minor|major>')
|
|
12
|
+
process.exit(1)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'))
|
|
16
|
+
const v = pkg.version
|
|
17
|
+
|
|
18
|
+
/** @param {string} ver @param {'patch'|'minor'|'major'} type */
|
|
19
|
+
function bumpSemver(ver, type) {
|
|
20
|
+
const m = ver.match(/^(\d+)\.(\d+)\.(\d+)$/)
|
|
21
|
+
if (!m) throw new Error(`Invalid semver base: ${ver}`)
|
|
22
|
+
let maj = Number(m[1])
|
|
23
|
+
let min = Number(m[2])
|
|
24
|
+
let pat = Number(m[3])
|
|
25
|
+
if (type === 'major') {
|
|
26
|
+
maj += 1
|
|
27
|
+
min = 0
|
|
28
|
+
pat = 0
|
|
29
|
+
} else if (type === 'minor') {
|
|
30
|
+
min += 1
|
|
31
|
+
pat = 0
|
|
32
|
+
} else if (type === 'patch') {
|
|
33
|
+
pat += 1
|
|
34
|
+
}
|
|
35
|
+
return `${maj}.${min}.${pat}`
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const plainMatch = v.match(/^(\d+\.\d+\.\d+)/)
|
|
39
|
+
if (!plainMatch) {
|
|
40
|
+
console.error(`[resolve-candidate-version] Could not parse version: ${v}`)
|
|
41
|
+
process.exit(1)
|
|
42
|
+
}
|
|
43
|
+
const plain = plainMatch[1]
|
|
44
|
+
|
|
45
|
+
/** @type {string} */
|
|
46
|
+
let targetBase
|
|
47
|
+
if (/^\d+\.\d+\.\d+-rc\.\d+$/.test(v)) {
|
|
48
|
+
targetBase = plain
|
|
49
|
+
} else {
|
|
50
|
+
targetBase = bumpSemver(plain, bump)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** @param {string} base @param {string[]} tags */
|
|
54
|
+
function maxRcForBase(base, tags) {
|
|
55
|
+
const prefixes = [`${base}-rc.`, `v${base}-rc.`]
|
|
56
|
+
let max = 0
|
|
57
|
+
for (const tag of tags) {
|
|
58
|
+
for (const prefix of prefixes) {
|
|
59
|
+
if (tag.startsWith(prefix)) {
|
|
60
|
+
const n = Number(tag.slice(prefix.length))
|
|
61
|
+
if (!Number.isNaN(n)) max = Math.max(max, n)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return max
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** @type {string[]} */
|
|
69
|
+
let tags = []
|
|
70
|
+
try {
|
|
71
|
+
tags = execSync('git tag -l', { encoding: 'utf8' })
|
|
72
|
+
.split('\n')
|
|
73
|
+
.map((t) => t.trim())
|
|
74
|
+
.filter(Boolean)
|
|
75
|
+
} catch {
|
|
76
|
+
tags = []
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const nextRc = maxRcForBase(targetBase, tags) + 1
|
|
80
|
+
process.stdout.write(`${targetBase}-rc.${nextRc}`)
|