mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 01:36:52 +00:00
Merge branch 'main' into next
This commit is contained in:
commit
e862b5a95e
20
.github/workflows/auto-merge.yml
vendored
20
.github/workflows/auto-merge.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: auto-merge
|
||||
name: Auto merge main -> next
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@ -13,17 +13,29 @@ jobs:
|
||||
push-commit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/create-github-app-token@v1
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ vars.NOCOBASE_APP_ID }}
|
||||
private-key: ${{ secrets.NOCOBASE_APP_PRIVATE_KEY }}
|
||||
repositories: nocobase,pro-plugins,${{ join(fromJSON(vars.PRO_PLUGIN_REPOS), ',') }},${{ join(fromJSON(vars.CUSTOM_PRO_PLUGIN_REPOS), ',') }}
|
||||
skip-token-revoke: true
|
||||
- name: Get GitHub App User ID
|
||||
id: get-user-id
|
||||
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: nocobase/nocobase
|
||||
ssh-key: ${{ secrets.NOCOBASE_DEPLOY_KEY }}
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
persist-credentials: true
|
||||
fetch-depth: 0
|
||||
- name: main -> next(nocobase)
|
||||
run: |
|
||||
git config --global user.email "actions@github.com"
|
||||
git config --global user.name "GitHub Actions Bot"
|
||||
git config --global user.name '${{ steps.app-token.outputs.app-slug }}[bot]'
|
||||
git config --global user.email '${{ steps.get-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com>'
|
||||
git checkout main
|
||||
git pull origin main
|
||||
git checkout next
|
||||
|
2
.github/workflows/build-docker-image.yml
vendored
2
.github/workflows/build-docker-image.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: Build Docker Image
|
||||
name: Build docker image
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
2
.github/workflows/build-pro-image.yml
vendored
2
.github/workflows/build-pro-image.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: Build Pro Image
|
||||
name: Build pro image
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
2
.github/workflows/changelog-and-release.yml
vendored
2
.github/workflows/changelog-and-release.yml
vendored
@ -70,7 +70,7 @@ jobs:
|
||||
- name: Run script
|
||||
shell: bash
|
||||
run: |
|
||||
node scripts/release/changelogAndRelease.js --ver ${{ inputs.version }}
|
||||
node scripts/release/changelogAndRelease.js --ver ${{ inputs.version }} --cmsURL ${{ secrets.CMS_URL }} --cmsToken ${{ secrets.CMS_TOKEN }}
|
||||
env:
|
||||
PRO_PLUGIN_REPOS: ${{ vars.PRO_PLUGIN_REPOS }}
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
|
56
.github/workflows/deploy-client-docs.yml
vendored
56
.github/workflows/deploy-client-docs.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: deploy client docs
|
||||
name: Deploy client docs
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@ -25,30 +25,30 @@ jobs:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
cache: 'yarn'
|
||||
- run: yarn install
|
||||
- name: Build zh-CN
|
||||
run: yarn doc build core/client --lang=zh-CN
|
||||
- name: Build en-US
|
||||
run: yarn doc build core/client --lang=en-US
|
||||
- name: Set tags
|
||||
id: set-tags
|
||||
run: |
|
||||
if [[ "${{ github.ref_name }}" == "main" ]]; then
|
||||
echo "::set-output name=tags::${{ github.ref_name }}"
|
||||
else
|
||||
echo "::set-output name=tags::pr-${{ github.event.pull_request.number }}"
|
||||
fi
|
||||
- name: copy files via ssh - ${{ steps.set-tags.outputs.tags }}
|
||||
uses: appleboy/scp-action@v0.1.4
|
||||
with:
|
||||
host: ${{ secrets.CN_CLIENT_HOST }}
|
||||
username: ${{ secrets.CN_CLIENT_USERNAME }}
|
||||
key: ${{ secrets.CN_CLIENT_KEY }}
|
||||
port: ${{ secrets.CN_CLIENT_PORT }}
|
||||
source: "packages/core/client/dist/*"
|
||||
target: ${{ secrets.CN_CLIENT_TARGET }}/${{ steps.set-tags.outputs.tags }}
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
cache: 'yarn'
|
||||
- run: yarn install
|
||||
- name: Build zh-CN
|
||||
run: yarn doc build core/client --lang=zh-CN
|
||||
- name: Build en-US
|
||||
run: yarn doc build core/client --lang=en-US
|
||||
- name: Set tags
|
||||
id: set-tags
|
||||
run: |
|
||||
if [[ "${{ github.ref_name }}" == "main" ]]; then
|
||||
echo "::set-output name=tags::${{ github.ref_name }}"
|
||||
else
|
||||
echo "::set-output name=tags::pr-${{ github.event.pull_request.number }}"
|
||||
fi
|
||||
- name: copy files via ssh - ${{ steps.set-tags.outputs.tags }}
|
||||
uses: appleboy/scp-action@v0.1.4
|
||||
with:
|
||||
host: ${{ secrets.CN_CLIENT_HOST }}
|
||||
username: ${{ secrets.CN_CLIENT_USERNAME }}
|
||||
key: ${{ secrets.CN_CLIENT_KEY }}
|
||||
port: ${{ secrets.CN_CLIENT_PORT }}
|
||||
source: 'packages/core/client/dist/*'
|
||||
target: ${{ secrets.CN_CLIENT_TARGET }}/${{ steps.set-tags.outputs.tags }}
|
||||
|
39
.github/workflows/get-nocobase-app-token.yml
vendored
39
.github/workflows/get-nocobase-app-token.yml
vendored
@ -1,39 +0,0 @@
|
||||
name: Get nocobase app github token
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
outputs:
|
||||
token:
|
||||
value: ${{ jobs.get-app-token.outputs.token }}
|
||||
user-id:
|
||||
value: ${{ jobs.get-app-token.outputs.user-id }}
|
||||
app-slug:
|
||||
value: ${{ jobs.get-app-token.outputs.app-slug }}
|
||||
|
||||
jobs:
|
||||
get-app-token:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
token: ${{ steps.encrypt-token.outputs.token }}
|
||||
app-slug: ${{ steps.app-token.outputs.app-slug }}
|
||||
user-id: ${{ steps.get-user-id.outputs.user-id }}
|
||||
steps:
|
||||
- uses: actions/create-github-app-token@v1
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ vars.NOCOBASE_APP_ID }}
|
||||
private-key: ${{ secrets.NOCOBASE_APP_PRIVATE_KEY }}
|
||||
repositories: nocobase,pro-plugins,${{ join(fromJSON(vars.PRO_PLUGIN_REPOS), ',') }}
|
||||
skip-token-revoke: true
|
||||
- name: Encrypt token
|
||||
id: encrypt-token
|
||||
shell: bash
|
||||
run: |
|
||||
APP_TOKEN=${{ steps.app-token.outputs.token }};
|
||||
ENCRYPTED_SECRET=$(echo -n "$APP_TOKEN" | openssl enc -aes-256-cbc -pbkdf2 -salt -k "${{ secrets.APP_TOKEN_ENCRYPTION_PASSWORD }}" | base64 -w 0);
|
||||
echo "token=$ENCRYPTED_SECRET" >> $GITHUB_OUTPUT
|
||||
- name: Get GitHub App User ID
|
||||
id: get-user-id
|
||||
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
@ -1,4 +1,4 @@
|
||||
name: manual-build-pr-docker-image
|
||||
name: Manual build pr docker image
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
2
.github/workflows/manual-build-pro-image.yml
vendored
2
.github/workflows/manual-build-pro-image.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: manual-build-pro-image
|
||||
name: Manual build pro image
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
@ -1,4 +1,4 @@
|
||||
name: Build Pro Plugin Docker Image
|
||||
name: Build pro plugin docker image
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
2
.github/workflows/manual-e2e.yml
vendored
2
.github/workflows/manual-e2e.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: manual-e2e
|
||||
name: Manual e2e
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
2
.github/workflows/manual-release.yml
vendored
2
.github/workflows/manual-release.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: manual-release
|
||||
name: Manual release
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
2
.github/workflows/nocobase-test-backend.yml
vendored
2
.github/workflows/nocobase-test-backend.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: NocoBase Backend Test
|
||||
name: NocoBase backend test
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
4
.github/workflows/nocobase-test-frontend.yml
vendored
4
.github/workflows/nocobase-test-frontend.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: NocoBase FrontEnd Test
|
||||
name: NocoBase frontEnd test
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@ -33,7 +33,7 @@ jobs:
|
||||
frontend-test:
|
||||
strategy:
|
||||
matrix:
|
||||
node_version: [ '18' ]
|
||||
node_version: ['18']
|
||||
runs-on: ubuntu-latest
|
||||
container: node:${{ matrix.node_version }}
|
||||
steps:
|
||||
|
4
.github/workflows/release-next.yml
vendored
4
.github/workflows/release-next.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: Release Next
|
||||
name: Release next
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@ -148,7 +148,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
git fetch
|
||||
node scripts/release/changelogAndRelease.js --ver alpha
|
||||
node scripts/release/changelogAndRelease.js --ver alpha --cmsURL ${{ secrets.CMS_URL }} --cmsToken ${{ secrets.CMS_TOKEN }}
|
||||
env:
|
||||
PRO_PLUGIN_REPOS: ${{ vars.NEXT_PRO_PLUGIN_REPOS }}
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
|
@ -3,8 +3,15 @@ const fs = require('fs/promises');
|
||||
const path = require('path');
|
||||
const { Command } = require('commander');
|
||||
const program = new Command();
|
||||
const axios = require('axios');
|
||||
|
||||
program.option('-f, --from [from]').option('-t, --to [to]').option('-v, --ver [ver]', '', 'beta').option('--test');
|
||||
program
|
||||
.option('-f, --from [from]')
|
||||
.option('-t, --to [to]')
|
||||
.option('-v, --ver [ver]', '', 'beta')
|
||||
.option('--test')
|
||||
.option('--cmsURL [url]')
|
||||
.option('--cmsToken [token]');
|
||||
program.parse(process.argv);
|
||||
|
||||
const header = {
|
||||
@ -99,7 +106,9 @@ async function parsePR(number, pkgType, cwd, pkg, retries = 10) {
|
||||
// gh pr view 5112 --json author,body,files
|
||||
let res;
|
||||
try {
|
||||
const { stdout } = await execa('gh', ['pr', 'view', number, '--json', 'author,body,files,baseRefName'], { cwd });
|
||||
const { stdout } = await execa('gh', ['pr', 'view', number, '--json', 'author,body,files,baseRefName,url'], {
|
||||
cwd,
|
||||
});
|
||||
res = stdout;
|
||||
} catch (error) {
|
||||
console.error(`Get PR #${number} failed, error: ${error.message}`);
|
||||
@ -110,7 +119,7 @@ async function parsePR(number, pkgType, cwd, pkg, retries = 10) {
|
||||
}
|
||||
return { number };
|
||||
}
|
||||
const { author, body, files, baseRefName } = JSON.parse(res);
|
||||
const { author, body, files, baseRefName, url } = JSON.parse(res);
|
||||
if (ver === 'alpha' && baseRefName !== 'next') {
|
||||
return { number };
|
||||
}
|
||||
@ -130,6 +139,7 @@ async function parsePR(number, pkgType, cwd, pkg, retries = 10) {
|
||||
author: author.login,
|
||||
moduleType: name?.includes('plugin-') ? 'plugin' : 'core',
|
||||
module: name,
|
||||
url,
|
||||
en: {
|
||||
module: displayName || pkgName,
|
||||
description,
|
||||
@ -187,17 +197,7 @@ function arrangeChangelogs(changelogs) {
|
||||
return result;
|
||||
}
|
||||
|
||||
async function collect() {
|
||||
let { from, to, ver = 'beta' } = program.opts();
|
||||
if (!from || !to) {
|
||||
// git tag -l --sort=version:refname | grep "v*-ver" | tail -2
|
||||
const tagPattern = `v*-${ver}`;
|
||||
const { stdout: tags } = await execa(`git tag -l --sort=version:refname | grep "${tagPattern}" | tail -2`, {
|
||||
shell: true,
|
||||
});
|
||||
[from, to] = tags.split('\n');
|
||||
}
|
||||
console.log(`From: ${from}, To: ${to}`);
|
||||
async function collect(from, to) {
|
||||
const changelogs = [];
|
||||
const get = async (changelogs, pkgType, cwd, pkg) => {
|
||||
const prs = await getPRList(from, to, cwd);
|
||||
@ -231,11 +231,11 @@ async function collect() {
|
||||
}
|
||||
}
|
||||
}
|
||||
return { changelogs: arrangeChangelogs(changelogs), from, to };
|
||||
return { changelogs: arrangeChangelogs(changelogs) };
|
||||
}
|
||||
|
||||
async function generateChangelog() {
|
||||
const { changelogs, from, to } = await collect();
|
||||
async function generateChangelog(changelogs) {
|
||||
const { test } = program.opts();
|
||||
const prTypeLocale = {
|
||||
'New feature': {
|
||||
en: '🎉 New Features',
|
||||
@ -275,13 +275,13 @@ async function generateChangelog() {
|
||||
const moduleResults = [];
|
||||
const lists = [];
|
||||
for (const changelog of moduleChangelogs) {
|
||||
const { number, author, pro } = changelog;
|
||||
const { number, author, pro, url } = changelog;
|
||||
const { description, docTitle, docLink } = changelog[lang];
|
||||
if (!description) {
|
||||
console.warn(`PR #${number} has no ${lang} changelog`);
|
||||
continue;
|
||||
}
|
||||
const pr = pro ? '' : ` ([#${number}](https://github.com/nocobase/nocobase/pull/${number}))`;
|
||||
const pr = pro && !test ? '' : ` ([#${number}](${url}))`;
|
||||
const doc = docTitle && docLink ? `${referenceLocale[lang]}[${docTitle}](${docLink})` : '';
|
||||
lists.push(`${description}${pr} by @${author}\n${doc}`);
|
||||
}
|
||||
@ -314,7 +314,7 @@ async function generateChangelog() {
|
||||
|
||||
const cn = generate(changelogs, 'cn');
|
||||
const en = generate(changelogs, 'en');
|
||||
return { cn, en, from, to };
|
||||
return { cn, en };
|
||||
}
|
||||
|
||||
async function writeChangelog(cn, en, from, to) {
|
||||
@ -335,6 +335,13 @@ async function writeChangelog(cn, en, from, to) {
|
||||
}
|
||||
|
||||
async function createRelease(cn, en, to) {
|
||||
const { stdout } = await execa('gh', ['release', 'list', '--json', 'tagName']);
|
||||
const releases = JSON.parse(stdout);
|
||||
const tags = releases.map((release) => release.tagName);
|
||||
if (tags.includes(to)) {
|
||||
console.log(`Release ${to} already exists`);
|
||||
return;
|
||||
}
|
||||
let { ver = 'beta' } = program.opts();
|
||||
// gh release create -t title -n note
|
||||
if (ver === 'alpha') {
|
||||
@ -344,21 +351,91 @@ async function createRelease(cn, en, to) {
|
||||
await execa('gh', ['release', 'create', to, '-t', to, '-n', `${en}\n---\n${cn}`]);
|
||||
}
|
||||
|
||||
async function writeChangelogAndCreateRelease() {
|
||||
let { ver = 'beta', test } = program.opts();
|
||||
const { cn, en, from, to } = await generateChangelog();
|
||||
if (!cn && !en) {
|
||||
throw new Error('No changelog generated');
|
||||
async function getExistsChangelog(from, to) {
|
||||
const get = async (lang) => {
|
||||
const file = lang === 'cn' ? 'CHANGELOG.zh-CN.md' : 'CHANGELOG.md';
|
||||
const oldChangelog = await fs.readFile(path.join(__dirname, `../../${file}`), 'utf8');
|
||||
if (!oldChangelog.includes(`## [${to}]`)) {
|
||||
return null;
|
||||
}
|
||||
const fromIndex = oldChangelog.indexOf(`## [${from}]`);
|
||||
const toIndex = oldChangelog.indexOf(`## [${to}]`);
|
||||
return oldChangelog.slice(toIndex, fromIndex);
|
||||
};
|
||||
const cn = await get('cn');
|
||||
const en = await get('en');
|
||||
return { cn, en };
|
||||
}
|
||||
|
||||
async function getVersion() {
|
||||
let { from, to, ver = 'beta' } = program.opts();
|
||||
if (!from || !to) {
|
||||
// git tag -l --sort=version:refname | grep "v*-ver" | tail -2
|
||||
const tagPattern = `v*-${ver}`;
|
||||
const { stdout: tags } = await execa(`git tag -l --sort=version:refname | grep "${tagPattern}" | tail -2`, {
|
||||
shell: true,
|
||||
});
|
||||
[from, to] = tags.split('\n');
|
||||
}
|
||||
if (test) {
|
||||
console.log(en);
|
||||
console.log(cn);
|
||||
console.log(`From: ${from}, To: ${to}`);
|
||||
return { from, to };
|
||||
}
|
||||
|
||||
async function postCMS(title, content, contentCN) {
|
||||
const { cmsToken, cmsURL } = program.opts();
|
||||
if (!cmsToken || !cmsURL) {
|
||||
console.error('No cmsToken or cmsURL provided');
|
||||
return;
|
||||
}
|
||||
if (ver === 'beta') {
|
||||
await axios.request({
|
||||
method: 'post',
|
||||
url: `${cmsURL}/api/articles:updateOrCreate`,
|
||||
headers: {
|
||||
Authorization: `Bearer ${cmsToken}`,
|
||||
},
|
||||
params: {
|
||||
filterKeys: ['title'],
|
||||
},
|
||||
data: {
|
||||
title,
|
||||
title_cn: title,
|
||||
content,
|
||||
content_cn: contentCN,
|
||||
tags: [4],
|
||||
status: 'drafted',
|
||||
author: 'nocobase [bot]',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function writeChangelogAndCreateRelease() {
|
||||
let { ver = 'beta', test } = program.opts();
|
||||
const { from, to } = await getVersion();
|
||||
let { cn, en } = await getExistsChangelog(from, to);
|
||||
let exists = false;
|
||||
if (cn || en) {
|
||||
exists = true;
|
||||
console.log('Changelog already exists');
|
||||
} else {
|
||||
const { changelogs } = await collect(from, to);
|
||||
const c = await generateChangelog(changelogs);
|
||||
cn = c.cn;
|
||||
en = c.en;
|
||||
if (!cn && !en) {
|
||||
console.error('No changelog generated');
|
||||
return;
|
||||
}
|
||||
}
|
||||
console.log(en);
|
||||
console.log(cn);
|
||||
if (test) {
|
||||
return;
|
||||
}
|
||||
if (ver === 'beta' && !exists) {
|
||||
await writeChangelog(cn, en, from, to);
|
||||
}
|
||||
await createRelease(cn, en, to);
|
||||
await postCMS(to, en, cn);
|
||||
}
|
||||
|
||||
writeChangelogAndCreateRelease();
|
||||
|
Loading…
Reference in New Issue
Block a user