diff --git a/.github/workflows/changelog-and-release.yml b/.github/workflows/changelog-and-release.yml new file mode 100644 index 0000000000..d4e219800c --- /dev/null +++ b/.github/workflows/changelog-and-release.yml @@ -0,0 +1,72 @@ +name: Write changelog and create release + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + workflow_dispatch: + push: + tags: + - 'v*-beta' + +jobs: + app-token: + uses: nocobase/nocobase/.github/workflows/get-nocobase-app-token.yml@main + secrets: inherit + write-changelog-and-release: + needs: + - app-token + runs-on: ubuntu-latest + steps: + - name: Decrypt app token + id: app-token + shell: bash + run: | + ENCRYPTED_SECRET=${{ needs.app-token.outputs.token }}; + APP_TOKEN=$(echo -n "$ENCRYPTED_SECRET" | base64 --decode | openssl enc -aes-256-cbc -pbkdf2 -d -salt -k "${{ secrets.APP_TOKEN_ENCRYPTION_PASSWORD }}"); + echo "token=$APP_TOKEN" >> $GITHUB_OUTPUT + - name: Checkout + uses: actions/checkout@v4 + with: + repository: nocobase/nocobase + token: ${{ steps.app-token.outputs.token }} + persist-credentials: true + fetch-depth: 0 + - name: Checkout pro-plugins + uses: actions/checkout@v4 + with: + repository: nocobase/pro-plugins + path: packages/pro-plugins + fetch-depth: 0 + token: ${{ steps.app-token.outputs.token }} + persist-credentials: true + - name: Clone pro repos + shell: bash + run: | + for repo in ${{ join(fromJSON(vars.PRO_PLUGIN_REPOS), ' ') }} + do + git clone -b main https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/nocobase/$repo.git packages/pro-plugins/@nocobase/$repo + done + - name: Set user + run: | + git config --global user.name '${{ needs.app-token.outputs.app-slug }}[bot]' + git config --global user.email '${{ needs.app-token.outputs.user-id }}+${{ needs.app-token.outputs.app-slug }}[bot]@users.noreply.github.com>' + - name: Set Node.js 18 + uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Install dependencies + run: yarn install --frozen-lockfile + - name: Run script + shell: bash + run: | + node scripts/release/changelogAndRelease.js + env: + PRO_PLUGIN_REPOS: ${{ vars.PRO_PLUGIN_REPOS }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} + - name: Commit and push + run: | + git add . + git commit -m "docs: update changelogs" + git push origin main diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/release.sh b/release.sh index 323c82a3a0..e5e7771d1e 100755 --- a/release.sh +++ b/release.sh @@ -28,7 +28,4 @@ cd ../../ git add . git commit -m "chore(versions): 😊 publish v$(jq -r '.version' lerna.json)" git tag v$(jq -r '.version' lerna.json) -yarn changelog --breaking-pattern "BREAKING CHANGE:" -git add . -git commit -m "chore: update changelog" # git push --atomic origin main v$(jq -r '.version' lerna.json) diff --git a/scripts/release/changelogAndRelease.js b/scripts/release/changelogAndRelease.js new file mode 100644 index 0000000000..e26fb216b1 --- /dev/null +++ b/scripts/release/changelogAndRelease.js @@ -0,0 +1,344 @@ +const execa = require('execa'); +const fs = require('fs/promises'); +const path = require('path'); +const { Command } = require('commander'); +const program = new Command(); + +program.option('-f, --from [from]').option('-t, --to [to]').option('-v, --ver [ver]'); +program.parse(process.argv); + +const header = { + en: `# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +`, + cn: `# 更新日志 + +本项目的所有重要更改都将记录在此文件中。 + +格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/), +并且本项目遵循 [语义化版本](https://semver.org/spec/v2.0.0.html)。 +`, +}; + +function parsePRBody(body, language) { + const regExp = new RegExp(`${language}[ ]?\\|[ ]?([^\\|]*)\\|`, 'g'); + const match = [...body.matchAll(regExp)]; + if (!match.length) { + return { + description: '', + docTitle: '', + docLink: '', + }; + } + const description = match[0]?.[1].trim() || ''; + const docLink = match[1]?.[1].trim(); + if (!docLink || docLink.startsWith('