mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 20:24:05 -08:00
ci: Setup a semi-automated release process (no-changelog) (#5504)
* ci: Setup a semi-automated release process (no-changelog) * create tag/release before deleting the temporary branch
This commit is contained in:
parent
5d74a2f89a
commit
3ae005cafe
52
.github/scripts/bump-versions.mjs
vendored
Normal file
52
.github/scripts/bump-versions.mjs
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
import semver from 'semver';
|
||||
import { writeFile, readFile } from 'fs/promises';
|
||||
import { resolve } from 'path';
|
||||
import child_process from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import assert from 'assert';
|
||||
|
||||
const exec = promisify(child_process.exec);
|
||||
|
||||
const rootDir = process.cwd();
|
||||
const releaseType = process.env.RELEASE_TYPE;
|
||||
assert.match(releaseType, /^(patch|minor|major)$/, 'Invalid RELEASE_TYPE');
|
||||
|
||||
// TODO: if releaseType is `auto` determine release type based on the changelog
|
||||
|
||||
const lastTag = (await exec('git describe --tags --match "n8n@*" --abbrev=0')).stdout.trim();
|
||||
const packages = JSON.parse((await exec('pnpm ls -r --only-projects --json')).stdout);
|
||||
|
||||
const packageMap = {};
|
||||
for (let { name, path, version, private: isPrivate, dependencies } of packages) {
|
||||
if (isPrivate && path !== rootDir) continue;
|
||||
if (path === rootDir) name = 'monorepo-root';
|
||||
|
||||
const isDirty = await exec(`git diff --quiet HEAD ${lastTag} -- ${path}`)
|
||||
.then(() => false)
|
||||
.catch((error) => true);
|
||||
|
||||
packageMap[name] = { path, isDirty, version };
|
||||
}
|
||||
|
||||
assert.ok(packageMap['n8n'].isDirty, 'No changes found since the last release');
|
||||
|
||||
// Keep the monorepo version up to date with the released version
|
||||
packageMap['monorepo-root'].version = packageMap['n8n'].version;
|
||||
|
||||
for (const packageName in packageMap) {
|
||||
const { path, version, isDirty } = packageMap[packageName];
|
||||
const packageFile = resolve(path, 'package.json');
|
||||
const packageJson = JSON.parse(await readFile(packageFile, 'utf-8'));
|
||||
|
||||
packageJson.version = packageMap[packageName].nextVersion =
|
||||
isDirty ||
|
||||
Object.keys(packageJson.dependencies).some(
|
||||
(dependencyName) => packageMap[dependencyName]?.isDirty,
|
||||
)
|
||||
? semver.inc(version, releaseType)
|
||||
: version;
|
||||
|
||||
await writeFile(packageFile, JSON.stringify(packageJson, null, 2) + '\n');
|
||||
}
|
||||
|
||||
console.log(packageMap['n8n'].nextVersion);
|
6
.github/scripts/package.json
vendored
Normal file
6
.github/scripts/package.json
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"semver": "^7.3.8",
|
||||
"conventional-changelog-cli": "^2.2.2"
|
||||
}
|
||||
}
|
2
.github/workflows/check-pr-title.yml
vendored
2
.github/workflows/check-pr-title.yml
vendored
|
@ -6,6 +6,8 @@ on:
|
|||
- opened
|
||||
- edited
|
||||
- synchronize
|
||||
branches:
|
||||
- '!release/*'
|
||||
|
||||
jobs:
|
||||
check-pr-title:
|
||||
|
|
69
.github/workflows/release-create-pr.yml
vendored
Normal file
69
.github/workflows/release-create-pr.yml
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
name: 'Release: Create Pull Request'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
base-branch:
|
||||
description: 'The branch to create this release PR from.'
|
||||
required: true
|
||||
default: 'master'
|
||||
|
||||
release-type:
|
||||
description: 'A SemVer release type.'
|
||||
required: true
|
||||
type: choice
|
||||
default: 'minor'
|
||||
options:
|
||||
- patch
|
||||
- minor
|
||||
|
||||
jobs:
|
||||
create-release-pr:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
timeout-minutes: 5
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.inputs.base-branch }}
|
||||
|
||||
- name: Push the base branch
|
||||
run: |
|
||||
git push -f origin ${{ github.event.inputs.base-branch }}:"release/${{ github.event.inputs.release-type }}"
|
||||
|
||||
- uses: pnpm/action-setup@v2.2.4
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
- run: npm install --prefix=.github/scripts --no-package-lock
|
||||
|
||||
- name: Bump package versions
|
||||
run: |
|
||||
echo "NEXT_RELEASE=$(node .github/scripts/bump-versions.mjs)" >> $GITHUB_ENV
|
||||
pnpm i --lockfile-only
|
||||
env:
|
||||
RELEASE_TYPE: ${{ github.event.inputs.release-type }}
|
||||
|
||||
- name: Generate Changelog
|
||||
run: npx conventional-changelog-cli -p angular -i CHANGELOG.md -s -t n8n@
|
||||
|
||||
- name: Push the release branch, and Create the PR
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
base: 'release/${{ github.event.inputs.release-type }}'
|
||||
branch: 'release/${{ env.NEXT_RELEASE }}'
|
||||
commit-message: ':rocket: Release ${{ env.NEXT_RELEASE }}'
|
||||
delete-branch: true
|
||||
labels: 'release'
|
||||
title: ':rocket: Release ${{ env.NEXT_RELEASE }}'
|
||||
# 'TODO: add generated changelog to the body. create a script to generate custom changelog'
|
||||
body: ''
|
||||
|
||||
# TODO: post PR link to slack
|
57
.github/workflows/release-publish.yml
vendored
Normal file
57
.github/workflows/release-publish.yml
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
name: 'Release: Publish'
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- closed
|
||||
branches:
|
||||
- 'release/patch'
|
||||
- 'release/minor'
|
||||
|
||||
jobs:
|
||||
publish-release:
|
||||
if: github.event.pull_request.merged == true
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: pnpm/action-setup@v2.2.4
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
cache: 'pnpm'
|
||||
- run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm build
|
||||
|
||||
- name: Publish to NPM
|
||||
run: |
|
||||
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
|
||||
pnpm publish -r --publish-branch ${{github.event.pull_request.base.ref}} --access public
|
||||
echo "RELEASE=$(node -e 'console.log(require("./package.json").version)')" >> $GITHUB_ENV
|
||||
|
||||
- name: Create Release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
commit: ${{github.event.pull_request.base.ref}}
|
||||
tag: 'n8n@${{env.RELEASE}}'
|
||||
|
||||
- name: Merge Release into 'master'
|
||||
run: |
|
||||
git fetch origin
|
||||
git checkout --track origin/master
|
||||
git config user.name github-actions
|
||||
git config user.email github-actions@github.com
|
||||
git merge --ff origin/${{github.event.pull_request.base.ref}}
|
||||
git push origin master
|
||||
git push origin :${{github.event.pull_request.base.ref}}
|
|
@ -11,15 +11,16 @@ Great that you are here and you want to contribute to n8n
|
|||
- [Development setup](#development-setup)
|
||||
- [Requirements](#requirements)
|
||||
- [Node.js](#nodejs)
|
||||
- [Build tools](#build-tools)
|
||||
- [pnpm](#pnpm)
|
||||
- [pnpm workspaces](#pnpm-workspaces)
|
||||
- [corepack](#corepack)
|
||||
- [Build tools](#build-tools)
|
||||
- [Actual n8n setup](#actual-n8n-setup)
|
||||
- [Start](#start)
|
||||
- [Development cycle](#development-cycle)
|
||||
- [Test suite](#test-suite)
|
||||
- [Releasing](#releasing)
|
||||
- [Create custom nodes](#create-custom-nodes)
|
||||
- [Create a new node to contribute to n8n](#create-a-new-node-to-contribute-to-n8n)
|
||||
- [Checklist before submitting a new node](#checklist-before-submitting-a-new-node)
|
||||
- [Extend documentation](#extend-documentation)
|
||||
- [Contributor License Agreement](#contributor-license-agreement)
|
||||
|
||||
|
@ -195,6 +196,22 @@ If that gets executed in one of the package folders it will only run the tests
|
|||
of this package. If it gets executed in the n8n-root folder it will run all
|
||||
tests of all packages.
|
||||
|
||||
## Releasing
|
||||
|
||||
To start a release, trigger [this workflow](https://github.com/n8n-io/n8n/actions/workflows/release-create-pr.yml) with the SemVer release type, and select a branch to cut this release from. This workflow will then
|
||||
|
||||
1. Bump versions of packages that have changed or have dependencies that have changed
|
||||
2. Update the Changelog
|
||||
3. Create a new branch called `release/${VERSION}`, and
|
||||
4. Create a new pull-request to track any further changes that need to be included in this release
|
||||
|
||||
Once ready to release, simply merge the pull-request.
|
||||
This triggers [another workflow](https://github.com/n8n-io/n8n/actions/workflows/release-publish.yml), that will
|
||||
|
||||
1. Build and publish the packages that have a new version in this release
|
||||
2. Create a new tag, and GitHub release from squashed release commit
|
||||
3. Merge the squashed release commit back into `master`
|
||||
|
||||
## Create custom nodes
|
||||
|
||||
Learn about [building nodes](https://docs.n8n.io/integrations/creating-nodes/) to create custom nodes for n8n. You can create community nodes and make them available using [npm](https://www.npmjs.com/).
|
||||
|
|
|
@ -34,10 +34,10 @@
|
|||
"test:e2e:all": "cross-env E2E_TESTS=true start-server-and-test start http://localhost:5678/favicon.ico 'cypress run --headless'"
|
||||
},
|
||||
"dependencies": {
|
||||
"n8n": "*"
|
||||
"n8n": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@n8n_io/eslint-config": "*",
|
||||
"@n8n_io/eslint-config": "workspace:*",
|
||||
"@ngneat/falso": "^6.1.0",
|
||||
"@types/jest": "^29.2.2",
|
||||
"@types/supertest": "^2.0.12",
|
||||
|
|
|
@ -170,10 +170,10 @@
|
|||
"lodash.unset": "^4.5.2",
|
||||
"luxon": "^3.1.0",
|
||||
"mysql2": "~2.3.3",
|
||||
"n8n-core": "~0.155.0",
|
||||
"n8n-editor-ui": "~0.182.0",
|
||||
"n8n-nodes-base": "~0.214.0",
|
||||
"n8n-workflow": "~0.137.0",
|
||||
"n8n-core": "workspace:*",
|
||||
"n8n-editor-ui": "workspace:*",
|
||||
"n8n-nodes-base": "workspace:*",
|
||||
"n8n-workflow": "workspace:*",
|
||||
"nodemailer": "^6.7.1",
|
||||
"oauth-1.0a": "^2.2.6",
|
||||
"open": "^7.0.0",
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
"form-data": "^4.0.0",
|
||||
"lodash.get": "^4.4.2",
|
||||
"mime-types": "^2.1.27",
|
||||
"n8n-workflow": "~0.137.0",
|
||||
"n8n-workflow": "workspace:*",
|
||||
"oauth-1.0a": "^2.2.6",
|
||||
"p-cancelable": "^2.0.0",
|
||||
"pretty-bytes": "^5.6.0",
|
||||
|
|
|
@ -63,8 +63,8 @@
|
|||
"lodash.set": "^4.3.2",
|
||||
"luxon": "^3.1.0",
|
||||
"monaco-editor": "^0.33.0",
|
||||
"n8n-design-system": "~0.54.0",
|
||||
"n8n-workflow": "~0.137.0",
|
||||
"n8n-design-system": "workspace:*",
|
||||
"n8n-workflow": "workspace:*",
|
||||
"normalize-wheel": "^1.0.1",
|
||||
"pinia": "^2.0.22",
|
||||
"prettier": "^2.8.3",
|
||||
|
|
|
@ -7,8 +7,6 @@ import { defineConfig as defineVitestConfig } from 'vitest/config';
|
|||
|
||||
import packageJSON from './package.json';
|
||||
|
||||
const isCI = process.env.CI === 'true';
|
||||
|
||||
const vendorChunks = ['vue', 'vue-router'];
|
||||
const n8nChunks = ['n8n-workflow', 'n8n-design-system'];
|
||||
const ignoreChunks = [
|
||||
|
@ -63,8 +61,6 @@ export default mergeConfig(
|
|||
},
|
||||
plugins: [
|
||||
vue(),
|
||||
...(!isCI
|
||||
? [
|
||||
legacy({
|
||||
targets: ['defaults', 'not IE 11'],
|
||||
}),
|
||||
|
@ -73,8 +69,6 @@ export default mergeConfig(
|
|||
customDistPath: (root: string, buildOutDir: string, base: string) =>
|
||||
`${root}/${buildOutDir}/assets/monaco-editor`,
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
],
|
||||
resolve: {
|
||||
alias: [
|
||||
|
@ -113,11 +107,9 @@ export default mergeConfig(
|
|||
},
|
||||
},
|
||||
build: {
|
||||
minify: !isCI,
|
||||
assetsInlineLimit: 0,
|
||||
sourcemap: false,
|
||||
rollupOptions: {
|
||||
treeshake: !isCI,
|
||||
output: {
|
||||
manualChunks: {
|
||||
vendor: vendorChunks,
|
||||
|
|
|
@ -59,8 +59,8 @@
|
|||
"change-case": "^4.1.1",
|
||||
"fast-glob": "^3.2.5",
|
||||
"inquirer": "^7.0.1",
|
||||
"n8n-core": "~0.155.0",
|
||||
"n8n-workflow": "~0.137.0",
|
||||
"n8n-core": "workspace:*",
|
||||
"n8n-workflow": "workspace:*",
|
||||
"oauth-1.0a": "^2.2.6",
|
||||
"replace-in-file": "^6.0.0",
|
||||
"request": "^2.88.2",
|
||||
|
|
|
@ -758,7 +758,7 @@
|
|||
"@types/xml2js": "^0.4.3",
|
||||
"eslint-plugin-n8n-nodes-base": "^1.12.0",
|
||||
"gulp": "^4.0.0",
|
||||
"n8n-workflow": "~0.137.0"
|
||||
"n8n-workflow": "workspace:*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@kafkajs/confluent-schema-registry": "1.0.6",
|
||||
|
@ -797,7 +797,7 @@
|
|||
"mqtt": "4.2.6",
|
||||
"mssql": "^8.1.2",
|
||||
"mysql2": "~2.3.0",
|
||||
"n8n-core": "~0.155.0",
|
||||
"n8n-core": "workspace:*",
|
||||
"node-html-markdown": "^1.1.3",
|
||||
"node-ssh": "^12.0.0",
|
||||
"nodemailer": "^6.7.1",
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
"dist/**/*"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@n8n_io/eslint-config": "",
|
||||
"@types/crypto-js": "^4.1.1",
|
||||
"@types/deep-equal": "^1.0.1",
|
||||
"@types/express": "^4.17.6",
|
||||
|
|
|
@ -26,7 +26,7 @@ importers:
|
|||
|
||||
.:
|
||||
specifiers:
|
||||
'@n8n_io/eslint-config': '*'
|
||||
'@n8n_io/eslint-config': workspace:*
|
||||
'@ngneat/falso': ^6.1.0
|
||||
'@types/jest': ^29.2.2
|
||||
'@types/supertest': ^2.0.12
|
||||
|
@ -37,7 +37,7 @@ importers:
|
|||
jest-environment-jsdom: ^29.4.2
|
||||
jest-mock: ^29.4.2
|
||||
jest-mock-extended: ^3.0.1
|
||||
n8n: '*'
|
||||
n8n: workspace:*
|
||||
nock: ^13.2.9
|
||||
node-fetch: ^2.6.7
|
||||
p-limit: ^3.1.0
|
||||
|
@ -208,10 +208,10 @@ importers:
|
|||
luxon: ^3.1.0
|
||||
mock-jwks: ^1.0.9
|
||||
mysql2: ~2.3.3
|
||||
n8n-core: ~0.155.0
|
||||
n8n-editor-ui: ~0.182.0
|
||||
n8n-nodes-base: ~0.214.0
|
||||
n8n-workflow: ~0.137.0
|
||||
n8n-core: workspace:*
|
||||
n8n-editor-ui: workspace:*
|
||||
n8n-nodes-base: workspace:*
|
||||
n8n-workflow: workspace:*
|
||||
nodemailer: ^6.7.1
|
||||
nodemon: ^2.0.2
|
||||
oauth-1.0a: ^2.2.6
|
||||
|
@ -405,7 +405,7 @@ importers:
|
|||
form-data: ^4.0.0
|
||||
lodash.get: ^4.4.2
|
||||
mime-types: ^2.1.27
|
||||
n8n-workflow: ~0.137.0
|
||||
n8n-workflow: workspace:*
|
||||
oauth-1.0a: ^2.2.6
|
||||
p-cancelable: ^2.0.0
|
||||
pretty-bytes: ^5.6.0
|
||||
|
@ -592,8 +592,8 @@ importers:
|
|||
lodash.set: ^4.3.2
|
||||
luxon: ^3.1.0
|
||||
monaco-editor: ^0.33.0
|
||||
n8n-design-system: ~0.54.0
|
||||
n8n-workflow: ~0.137.0
|
||||
n8n-design-system: workspace:*
|
||||
n8n-workflow: workspace:*
|
||||
normalize-wheel: ^1.0.1
|
||||
pinia: ^2.0.22
|
||||
prettier: ^2.8.3
|
||||
|
@ -723,8 +723,8 @@ importers:
|
|||
change-case: ^4.1.1
|
||||
fast-glob: ^3.2.5
|
||||
inquirer: ^7.0.1
|
||||
n8n-core: ~0.155.0
|
||||
n8n-workflow: ~0.137.0
|
||||
n8n-core: workspace:*
|
||||
n8n-workflow: workspace:*
|
||||
oauth-1.0a: ^2.2.6
|
||||
replace-in-file: ^6.0.0
|
||||
request: ^2.88.2
|
||||
|
@ -816,8 +816,8 @@ importers:
|
|||
mqtt: 4.2.6
|
||||
mssql: ^8.1.2
|
||||
mysql2: ~2.3.0
|
||||
n8n-core: ~0.155.0
|
||||
n8n-workflow: ~0.137.0
|
||||
n8n-core: workspace:*
|
||||
n8n-workflow: workspace:*
|
||||
node-html-markdown: ^1.1.3
|
||||
node-ssh: ^12.0.0
|
||||
nodemailer: ^6.7.1
|
||||
|
@ -933,7 +933,6 @@ importers:
|
|||
|
||||
packages/workflow:
|
||||
specifiers:
|
||||
'@n8n_io/eslint-config': ''
|
||||
'@n8n_io/riot-tmpl': ^2.0.0
|
||||
'@types/crypto-js': ^4.1.1
|
||||
'@types/deep-equal': ^1.0.1
|
||||
|
@ -978,7 +977,6 @@ importers:
|
|||
transliteration: 2.3.5
|
||||
xml2js: 0.4.23
|
||||
devDependencies:
|
||||
'@n8n_io/eslint-config': link:../@n8n_io/eslint-config
|
||||
'@types/crypto-js': 4.1.1
|
||||
'@types/deep-equal': 1.0.1
|
||||
'@types/express': 4.17.14
|
||||
|
|
Loading…
Reference in a new issue