From af70f1fc35ef19e296702a855ad686659a11786a Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Sun, 3 Aug 2025 13:53:17 +0200 Subject: [PATCH 1/2] task: Add tooling for automating releases --- package-lock.json | 7 ++++--- package.json | 5 ++++- scripts/.eslintrc.cjs | 8 ++++++++ scripts/finishRelease.js | 36 ++++++++++++++++++++++++++++++++++++ scripts/prepareRelease.js | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 scripts/.eslintrc.cjs create mode 100644 scripts/finishRelease.js create mode 100644 scripts/prepareRelease.js diff --git a/package-lock.json b/package-lock.json index 71c5addf..7c4f5b58 100644 --- a/package-lock.json +++ b/package-lock.json @@ -104,6 +104,7 @@ "eslint-plugin-simple-import-sort": "^12.1.1", "husky": "^9.1.7", "sass": "^1.77.8", + "semver": "^7.7.2", "stylelint": "^16.9.0", "stylelint-config-clean-order": "^6.1.0", "stylelint-config-standard": "^36.0.1", @@ -14866,9 +14867,9 @@ } }, "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "license": "ISC", "bin": { "semver": "bin/semver.js" diff --git a/package.json b/package.json index 9d42ef45..5a7e9a3e 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,9 @@ "test:coverage": "vitest run --coverage --coverage.reporter=text", "test:debug": "vitest --inspect-brk --no-file-parallelism", "test": "vitest run --reporter verbose", - "gen:component": "node generateComponent.js" + "gen:component": "node generateComponent.js", + "release:prepare": "node scripts/prepareRelease.js", + "release:finish": "node scripts/finishRelease.js" }, "dependencies": { "@convex-dev/auth": "^0.0.80", @@ -120,6 +122,7 @@ "eslint-plugin-simple-import-sort": "^12.1.1", "husky": "^9.1.7", "sass": "^1.77.8", + "semver": "^7.7.2", "stylelint": "^16.9.0", "stylelint-config-clean-order": "^6.1.0", "stylelint-config-standard": "^36.0.1", diff --git a/scripts/.eslintrc.cjs b/scripts/.eslintrc.cjs new file mode 100644 index 00000000..08af8012 --- /dev/null +++ b/scripts/.eslintrc.cjs @@ -0,0 +1,8 @@ +module.exports = { + env: { + node: true, + }, + rules: { + 'no-console': 'off' + } +}; diff --git a/scripts/finishRelease.js b/scripts/finishRelease.js new file mode 100644 index 00000000..81354313 --- /dev/null +++ b/scripts/finishRelease.js @@ -0,0 +1,36 @@ +import { execSync } from 'child_process'; +import semver from 'semver'; + +const version = process.argv[2]; +if (!version || !semver.valid(version)) { + console.error('Please provide a valid semver version (e.g., 1.0.0)!'); + process.exit(1); +} + +const releaseBranch = `release-v${version}`; +const tagName = `v${version}`; + +try { + console.log(`\nPublishing release ${version}...\n`); + + execSync('git checkout main', { stdio: 'inherit' }); + execSync('git pull origin main', { stdio: 'inherit' }); + execSync(`git merge --no-ff ${releaseBranch} -m "Merge release ${version} into main"`, { stdio: 'inherit' }); + + execSync(`git tag -a ${tagName} -m "Release ${tagName}"`, { stdio: 'inherit' }); + execSync('git push origin main'); + execSync(`git push origin ${tagName}`); + + execSync('git checkout develop', { stdio: 'inherit' }); + execSync('git pull origin develop', { stdio: 'inherit' }); + execSync(`git merge --no-ff ${releaseBranch} -m "Merge release ${version} into develop"`, { stdio: 'inherit' }); + execSync('git push origin develop'); + + execSync(`git branch -d ${releaseBranch}`, { stdio: 'inherit' }); + execSync(`git push origin --delete ${releaseBranch}`, { stdio: 'inherit' }); + + console.log(`\nāœ… Release ${version} completed and cleaned up.\n`); +} catch (err) { + console.error('āŒ Failed to finish release:', err.message); + process.exit(1); +} diff --git a/scripts/prepareRelease.js b/scripts/prepareRelease.js new file mode 100644 index 00000000..c9ea1fde --- /dev/null +++ b/scripts/prepareRelease.js @@ -0,0 +1,33 @@ +import { execSync } from 'child_process'; +import semver from 'semver'; + +const version = process.argv[2]; +if (!version || !semver.valid(version)) { + console.error('Please provide a valid semver version (e.g., 1.0.0)!'); + process.exit(1); +} + +const releaseBranch = `release-v${version}`; + +try { + console.log(`\nšŸš€ Preparing release ${version}...\n`); + + execSync('git checkout develop', { stdio: 'inherit' }); + execSync('git pull origin develop', { stdio: 'inherit' }); + + execSync(`git checkout -b ${releaseBranch}`, { stdio: 'inherit' }); + + execSync(`npm version ${version} --no-git-tag-version`, { stdio: 'inherit' }); + execSync(`git commit -am "Prepare release v${version}"`, { stdio: 'inherit' }); + + execSync(`git push --set-upstream origin ${releaseBranch}`, { stdio: 'inherit' }); + + console.log(`\nšŸ“¦ Creating pull request from '${releaseBranch}' to 'main'...\n`); + + execSync(`gh pr create --base main --head ${releaseBranch} --title "Release v${version}" --body "This PR prepares release v${version}."`, { stdio: 'inherit' }); + + console.log(`\nāœ… Release branch '${releaseBranch}' created and PR opened.\n`); +} catch (err) { + console.error('āŒ Failed to prepare release:', err.message); + process.exit(1); +} From bec14972f69e9d2056a27275cd64f03769eb61d2 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Sun, 3 Aug 2025 13:53:52 +0200 Subject: [PATCH 2/2] task: Move generate component script to /scripts --- package.json | 2 +- generateComponent.js => scripts/generateComponent.js | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename generateComponent.js => scripts/generateComponent.js (100%) diff --git a/package.json b/package.json index 5a7e9a3e..b30d83a7 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "test:coverage": "vitest run --coverage --coverage.reporter=text", "test:debug": "vitest --inspect-brk --no-file-parallelism", "test": "vitest run --reporter verbose", - "gen:component": "node generateComponent.js", + "gen:component": "node scripts/generateComponent.js", "release:prepare": "node scripts/prepareRelease.js", "release:finish": "node scripts/finishRelease.js" }, diff --git a/generateComponent.js b/scripts/generateComponent.js similarity index 100% rename from generateComponent.js rename to scripts/generateComponent.js