From 038aebea713cd77bb38d4727170cdf571e82f230 Mon Sep 17 00:00:00 2001 From: Markus Rudolph Date: Mon, 18 Nov 2024 08:58:49 +0100 Subject: [PATCH] Create a release process (#36) * Copied deployment config from Langium * Add "Update versions" script * Add publish GH action * Run `npm pkg fix` --- .github/workflows/publish.yml | 41 +++++++ RELEASE.md | 19 +++ examples/lox/package.json | 7 +- examples/ox/package.json | 19 +-- package-lock.json | 39 +++++-- package.json | 4 +- packages/typir-langium/package-lock.json | 140 ----------------------- packages/typir-langium/package.json | 12 +- packages/typir/package.json | 12 +- scripts/update-version.js | 37 ++++++ 10 files changed, 152 insertions(+), 178 deletions(-) create mode 100644 .github/workflows/publish.yml create mode 100644 RELEASE.md delete mode 100644 packages/typir-langium/package-lock.json create mode 100644 scripts/update-version.js diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..15200b9 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,41 @@ +name: Publish + +permissions: + id-token: write + +on: + release: + types: [published] + +jobs: + publish: + name: Typir Publish + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: '18.x' + registry-url: 'https://registry.npmjs.org' + - name: Build + shell: bash + run: | + npm ci + npm run clean + npm run build + - name: Test + if: success() || failure() + shell: bash + run: | + npm run test:run + - name: Publish NPM Packages + shell: bash + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + # Update the following list when a new npm package is added + run: | + npm run publish:latest --provenance --workspace=typir + npm run publish:latest --provenance --workspace=typir-langium diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000..47c0b44 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,19 @@ +# Release Process + +The release process is mostly automated and requires running only a few commands. After commiting, pushing, tagging and releasing the changes, a GitHub Action will publish all npm packages. + +1. Pull the latest changes from the main branch +2. Create a new branch +3. Uplift the package versions by running `npm version major|minor|patch --no-git-tag-version --workspaces` +4. Update the dependency versions by running `npm run version:dependencies` +5. Create a PR with your updated changes, get a review and merge it +6. Create a version tag on the latest commit on main and push it + + ```bash + git checkout main + git pull origin main + git tag + git push origin + ``` + +7. Create a [GitHub release](https://github.com/TypeFox/typir/releases) from the new tag (this will trigger the Github Action and publish all artifacts automatically). diff --git a/examples/lox/package.json b/examples/lox/package.json index e377add..94253c5 100644 --- a/examples/lox/package.json +++ b/examples/lox/package.json @@ -1,8 +1,9 @@ { - "name": "lox", + "name": "typir-example-lox", "displayName": "lox", "version": "0.0.1", - "description": "Please enter a brief description here", + "private": true, + "description": "", "author": { "name": "TypeFox", "url": "https://www.typefox.io" @@ -74,6 +75,6 @@ ], "main": "./out/extension/main.cjs", "bin": { - "ox-cli": "./out/cli/main.js" + "ox-cli": "out/cli/main.js" } } diff --git a/examples/ox/package.json b/examples/ox/package.json index 9470ba6..3832547 100644 --- a/examples/ox/package.json +++ b/examples/ox/package.json @@ -1,8 +1,9 @@ { - "name": "ox", - "displayName": "Ox", + "name": "typir-example-ox", + "displayName": "ox", "version": "0.0.1", - "description": "Please enter a brief description here", + "private": true, + "description": "", "author": { "name": "TypeFox", "url": "https://www.typefox.io" @@ -27,11 +28,11 @@ "watch": "concurrently -n tsc,esbuild -c blue,yellow \"tsc -b tsconfig.json --watch\" \"node esbuild.mjs --watch\"" }, "dependencies": { - "commander": "~12.1.0", - "langium": "~3.2.0", - "typir-langium": "~0.0.1", - "vscode-languageclient": "~9.0.1", - "vscode-languageserver": "~9.0.1" + "commander": "~12.1.0", + "langium": "~3.2.0", + "typir-langium": "~0.0.1", + "vscode-languageclient": "~9.0.1", + "vscode-languageserver": "~9.0.1" }, "devDependencies": { "@types/vscode": "~1.94.0", @@ -74,6 +75,6 @@ ], "main": "./out/extension/main.cjs", "bin": { - "ox-cli": "./out/cli/main.js" + "ox-cli": "out/cli/main.js" } } diff --git a/package-lock.json b/package-lock.json index 8e66b56..46970e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "esbuild": "~0.24.0", "eslint": "~8.57.1", "eslint-plugin-header": "~3.1.1", + "fs-extra": "^11.2.0", "shx": "~0.3.4", "typescript": "~5.5.4", "vitest": "~2.1.2" @@ -34,6 +35,7 @@ } }, "examples/lox": { + "name": "typir-example-lox", "version": "0.0.1", "license": "MIT", "dependencies": { @@ -63,6 +65,7 @@ } }, "examples/ox": { + "name": "typir-example-ox", "version": "0.0.1", "license": "MIT", "dependencies": { @@ -2051,9 +2054,9 @@ "dev": true }, "node_modules/fs-extra": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", - "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", @@ -2413,6 +2416,20 @@ "node": ">=16.0.0" } }, + "node_modules/langium-cli/node_modules/fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, "node_modules/langium-railroad": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/langium-railroad/-/langium-railroad-3.2.0.tgz", @@ -2474,10 +2491,6 @@ "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==", "dev": true }, - "node_modules/lox": { - "resolved": "examples/lox", - "link": true - }, "node_modules/magic-string": { "version": "0.30.11", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", @@ -2595,10 +2608,6 @@ "node": ">= 0.8.0" } }, - "node_modules/ox": { - "resolved": "examples/ox", - "link": true - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -3287,6 +3296,14 @@ "resolved": "packages/typir", "link": true }, + "node_modules/typir-example-lox": { + "resolved": "examples/lox", + "link": true + }, + "node_modules/typir-example-ox": { + "resolved": "examples/ox", + "link": true + }, "node_modules/typir-langium": { "resolved": "packages/typir-langium", "link": true diff --git a/package.json b/package.json index 62eee7c..ad67155 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "langium:generate": "npm run langium:generate --workspace=examples/ox --workspace=examples/lox", "langium:watch": "npm run langium:watch --workspace=examples/ox --workspace=examples/lox", "vscode:prepublish": "npm run build && npm run lint", - "reset:repo": "git clean -f -X -d" + "reset:repo": "git clean -f -X -d", + "version:dependencies": "node ./scripts/update-version.js && npm install" }, "devDependencies": { "@types/node": "~18.19.55", @@ -38,6 +39,7 @@ "esbuild": "~0.24.0", "eslint": "~8.57.1", "eslint-plugin-header": "~3.1.1", + "fs-extra": "^11.2.0", "shx": "~0.3.4", "typescript": "~5.5.4", "vitest": "~2.1.2" diff --git a/packages/typir-langium/package-lock.json b/packages/typir-langium/package-lock.json deleted file mode 100644 index d348e89..0000000 --- a/packages/typir-langium/package-lock.json +++ /dev/null @@ -1,140 +0,0 @@ -{ - "name": "typir-langium", - "version": "0.0.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "typir-langium", - "version": "0.0.1", - "license": "MIT", - "dependencies": { - "langium": "^3.2.0" - }, - "engines": { - "node": ">= 18.0.0" - } - }, - "node_modules/@chevrotain/cst-dts-gen": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", - "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", - "dependencies": { - "@chevrotain/gast": "11.0.3", - "@chevrotain/types": "11.0.3", - "lodash-es": "4.17.21" - } - }, - "node_modules/@chevrotain/gast": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz", - "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", - "dependencies": { - "@chevrotain/types": "11.0.3", - "lodash-es": "4.17.21" - } - }, - "node_modules/@chevrotain/regexp-to-ast": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", - "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==" - }, - "node_modules/@chevrotain/types": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", - "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==" - }, - "node_modules/@chevrotain/utils": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz", - "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==" - }, - "node_modules/chevrotain": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", - "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", - "dependencies": { - "@chevrotain/cst-dts-gen": "11.0.3", - "@chevrotain/gast": "11.0.3", - "@chevrotain/regexp-to-ast": "11.0.3", - "@chevrotain/types": "11.0.3", - "@chevrotain/utils": "11.0.3", - "lodash-es": "4.17.21" - } - }, - "node_modules/chevrotain-allstar": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", - "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", - "dependencies": { - "lodash-es": "^4.17.21" - }, - "peerDependencies": { - "chevrotain": "^11.0.0" - } - }, - "node_modules/langium": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/langium/-/langium-3.2.0.tgz", - "integrity": "sha512-HxAPgCVC7X+dCN99QKlZMEoaLW4s/mt0IImYrP6ooEBOMh8lJYdFNNSpJ5NIOE+WFwQd3xa2phTJDmJhOWVR7A==", - "dependencies": { - "chevrotain": "~11.0.3", - "chevrotain-allstar": "~0.3.0", - "vscode-languageserver": "~9.0.1", - "vscode-languageserver-textdocument": "~1.0.11", - "vscode-uri": "~3.0.8" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" - }, - "node_modules/vscode-jsonrpc": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", - "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/vscode-languageserver": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", - "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", - "dependencies": { - "vscode-languageserver-protocol": "3.17.5" - }, - "bin": { - "installServerIntoExtension": "bin/installServerIntoExtension" - } - }, - "node_modules/vscode-languageserver-protocol": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", - "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", - "dependencies": { - "vscode-jsonrpc": "8.2.0", - "vscode-languageserver-types": "3.17.5" - } - }, - "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", - "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==" - }, - "node_modules/vscode-languageserver-types": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", - "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==" - }, - "node_modules/vscode-uri": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", - "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==" - } - } -} diff --git a/packages/typir-langium/package.json b/packages/typir-langium/package.json index 0e0c5f8..ffce4cb 100644 --- a/packages/typir-langium/package.json +++ b/packages/typir-langium/package.json @@ -31,21 +31,19 @@ ], "files": [ "lib", - "src", - "node.js", - "node.d.ts", - "test.js", - "test.d.ts" + "src" ], "scripts": { "clean": "shx rm -rf lib out coverage", "build": "tsc", "watch": "tsc --watch", - "lint": "eslint src test --ext .ts" + "lint": "eslint src test --ext .ts", + "publish:next": "npm --no-git-tag-version version \"$(semver $npm_package_version -i minor)-next.$(git rev-parse --short HEAD)\" && npm publish --tag next", + "publish:latest": "npm publish --tag latest --access public" }, "repository": { "type": "git", - "url": "https://github.com/TypeFox/typir/", + "url": "git+https://github.com/TypeFox/typir.git", "directory": "packages/typir-langium" }, "bugs": "https://github.com/TypeFox/typir/issues", diff --git a/packages/typir/package.json b/packages/typir/package.json index 18d10e4..7eb7653 100644 --- a/packages/typir/package.json +++ b/packages/typir/package.json @@ -31,21 +31,19 @@ ], "files": [ "lib", - "src", - "node.js", - "node.d.ts", - "test.js", - "test.d.ts" + "src" ], "scripts": { "clean": "shx rm -rf lib out coverage", "build": "tsc", "watch": "tsc --watch", - "lint": "eslint src test --ext .ts" + "lint": "eslint src test --ext .ts", + "publish:next": "npm --no-git-tag-version version \"$(semver $npm_package_version -i minor)-next.$(git rev-parse --short HEAD)\" && npm publish --tag next", + "publish:latest": "npm publish --tag latest --access public" }, "repository": { "type": "git", - "url": "https://github.com/TypeFox/typir/", + "url": "git+https://github.com/TypeFox/typir.git", "directory": "packages/typir" }, "bugs": "https://github.com/TypeFox/typir/issues" diff --git a/scripts/update-version.js b/scripts/update-version.js new file mode 100644 index 0000000..2bd0acd --- /dev/null +++ b/scripts/update-version.js @@ -0,0 +1,37 @@ +import fs from 'fs-extra'; +import path from 'path'; + +async function runUpdate() { + const versions = await Promise.all([ + getVersionOf('typir'), + getVersionOf('typir-langium'), + ]); + await Promise.all([ + replaceAll('typir', true, versions), + replaceAll('typir-langium', true, versions), + replaceAll('ox', false, versions), + replaceAll('lox', false, versions), + ]); +} + +async function replaceAll(project, pkg, versions) { + const path = getPath(project, pkg); + let content = await fs.readFile(path, 'utf-8'); + versions.forEach(([project, version]) => { + const regex = new RegExp("(?<=\"" + project + "\": \"[~\\^]?)\\d+\\.\\d+\\.\\d+", "g"); + content = content.replace(regex, version); + }); + await fs.writeFile(path, content); +} + +function getPath(project, pkg) { + return path.join(pkg ? 'packages' : 'examples', project, 'package.json'); +} + +async function getVersionOf(project) { + const typirPath = getPath(project, true); + const typirPackage = await fs.readJson(typirPath); + return [project, typirPackage.version]; +} + +runUpdate();