diff --git a/.github/workflows/node-release-no-provenance.yml b/.github/workflows/node-release-no-provenance.yml new file mode 100644 index 0000000..b9ce658 --- /dev/null +++ b/.github/workflows/node-release-no-provenance.yml @@ -0,0 +1,96 @@ +name: Node.js Release + +on: + workflow_call: + secrets: + NPM_TOKEN: + description: 'npm token' + required: true + GIT_TOKEN: + description: 'github personal token' + required: true + + inputs: + checkTest: + type: boolean + description: whether run test before release + default: false + + dryRun: + type: boolean + description: pass dry-run to semantic-release + default: false + + install: + type: string + description: 'Install dependencies script' + default: 'npm i --no-package-lock --no-fund --force && rm -rf package-lock.json' + + action_ref: + type: string + description: 'Branch name for node-modules/github-actions, for test purpose' + default: master + +jobs: + Release: + permissions: + contents: write + deployments: write + runs-on: ubuntu-latest + defaults: + run: + working-directory: main_repo + + concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + + steps: + # Checkout action repository + - name: Checkout action repository + uses: actions/checkout@v4 + with: + repository: node-modules/github-actions + path: action_repo + ref: ${{ inputs.action_ref }} + + # Checkout project repository + - name: Checkout project repository + uses: actions/checkout@v4 + with: + path: main_repo + token: ${{ secrets.GIT_TOKEN }} + + # Setup Node.js environment + - name: Setup Node.js + uses: actions/setup-node@v4 + + # Install action dependencies + - name: Install action dependencies + run: npm i --no-package-lock --no-fund --omit=dev + working-directory: action_repo/scripts/release + + # Install dependencies + - name: Install dependencies + run: ${{ inputs.install }} + + # Run Test Only + - name: Run Test + run: npm test + if: inputs.checkTest + + - name: Semantic Release + id: release + run: node ../action_repo/scripts/release/index.js + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + DRYRUN: ${{ inputs.dryRun }} + + - name: Publish ${{ steps.release.outputs.name }}@${{ steps.release.outputs.release_version }} + if: steps.release.outputs.release_version && !inputs.dryRun + run: | + echo ${{ steps.release.outputs.name }} + echo ${{ steps.release.outputs.release_version }} + echo ${{ steps.release.outputs.registry }} + echo ${{ steps.release.outputs.cnpm_sync_url }} diff --git a/.github/workflows/node-release.yml b/.github/workflows/node-release.yml index 2c8597b..82fda97 100644 --- a/.github/workflows/node-release.yml +++ b/.github/workflows/node-release.yml @@ -14,7 +14,7 @@ on: checkTest: type: boolean description: whether run test before release - default: true + default: false dryRun: type: boolean @@ -24,15 +24,19 @@ on: install: type: string description: 'Install dependencies script' - default: 'npm i --no-package-lock --no-fund' + default: 'npm i --no-package-lock --no-fund --force && rm -rf package-lock.json' action_ref: type: string - description: 'Branch name for artusjs/github-actions, for test purpose' + description: 'Branch name for node-modules/github-actions, for test purpose' default: master jobs: Release: + permissions: + contents: write + id-token: write + deployments: write runs-on: ubuntu-latest defaults: run: @@ -45,22 +49,24 @@ jobs: steps: # Checkout action repository - name: Checkout action repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: - repository: artusjs/github-actions + repository: node-modules/github-actions path: action_repo ref: ${{ inputs.action_ref }} # Checkout project repository - name: Checkout project repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: main_repo token: ${{ secrets.GIT_TOKEN }} # Setup Node.js environment - name: Setup Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 + with: + node-version: lts/* # Install action dependencies - name: Install action dependencies @@ -83,6 +89,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} DRYRUN: ${{ inputs.dryRun }} + NPM_CONFIG_PROVENANCE: true - name: Publish ${{ steps.release.outputs.name }}@${{ steps.release.outputs.release_version }} if: steps.release.outputs.release_version && !inputs.dryRun diff --git a/.github/workflows/node-test-mysql.yml b/.github/workflows/node-test-mysql.yml new file mode 100644 index 0000000..9932548 --- /dev/null +++ b/.github/workflows/node-test-mysql.yml @@ -0,0 +1,147 @@ +name: Node.js Unit Test + +on: + workflow_call: + secrets: + CODECOV_TOKEN: + description: 'codecov token' + required: false + + inputs: + os: + type: string + description: 'Operator System, such as: ubuntu-latest, macos-latest' + default: 'ubuntu-latest' + + version: + type: string + description: 'Node.js Version, such as 18, 20, 22' + default: '18, 20, 22' + + install: + type: string + description: 'Install dependencies script' + default: 'npm i --no-package-lock --no-fund' + + test: + type: string + description: 'test script, such as: npm test, npm run ci' + default: 'npm run ci' + + action_ref: + type: string + description: 'Branch name for node-modules/github-actions, for test purpose' + default: master + + mysql_version: + type: string + description: 'mysql version, default to 5' + default: '5' + +jobs: + Setup: + runs-on: ubuntu-latest + outputs: + os: ${{ steps.handler.outputs.os }} + version: ${{ steps.handler.outputs.version }} + mysql_version: ${{ steps.handler.outputs.mysql_version }} + + steps: + # Checkout action repository + - name: Checkout + uses: actions/checkout@v4 + with: + repository: node-modules/github-actions + path: action_repo + ref: ${{ inputs.action_ref }} + + # Setup Node.js environment + - name: Setup Node.js + uses: actions/setup-node@v4 + + # Install dependencies + - name: Install dependencies + run: npm i --no-package-lock --no-fund + working-directory: action_repo/scripts/test + + # Normalize inputs style + - name: Convert Inputs to Matrix + id: handler + run: node action_repo/scripts/test/index.js + env: + INPUT_OS: ${{ inputs.os }} + INPUT_VERSION: ${{ inputs.version }} + INPUT_MYSQL_VERSION: ${{ inputs.mysql_version }} + + Test: + needs: Setup + strategy: + fail-fast: false + matrix: + os: ${{ fromJSON(needs.setup.outputs.os) }} + version: ${{ fromJSON(needs.setup.outputs.version) }} + mysql_version: ${{ fromJSON(needs.setup.outputs.mysql_version) }} + + name: Test (${{ matrix.os }}, ${{ matrix.version }}, mysql@${{ matrix.mysql_version }}) + runs-on: ${{ matrix.os }} + + services: + mysql: + image: mysql:${{ matrix.mysql_version }} + env: + MYSQL_ALLOW_EMPTY_PASSWORD: true + MYSQL_DATABASE: test + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=5 + + redis: + # https://docs.github.com/en/actions/using-containerized-services/about-service-containers#example-mapping-redis-ports + image: redis + ports: + # Opens tcp port 6379 on the host and service container + - 6379:6379 + + concurrency: + group: ${{ github.workflow }}-#${{ github.event.pull_request.number || github.ref }}-(${{ matrix.os }}, ${{ matrix.version }}, mysql@${{ matrix.mysql_version }}) + cancel-in-progress: true + + steps: + - name: Checkout Git Source + uses: actions/checkout@v4 + + - name: Calculate Architecture + uses: actions/github-script@v7 + id: calculate_architecture + with: + result-encoding: string + script: | + const osVersion = '${{ matrix.os }}'; + const isMacOS = osVersion === 'macos-latest' || osVersion.startsWith('macos'); + const nodeVersion = parseInt('${{ matrix.version }}'.split('.')[0]); + if (isMacOS && nodeVersion <= 14) { + return 'x64'; + } else { + return ''; + } + + - name: Use Node.js ${{ matrix.version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.version }} + architecture: ${{ steps.calculate_architecture.outputs.result }} + check-latest: true + + - name: Install Dependencies + run: ${{ inputs.install }} + + - name: Run Lint + run: npm run lint --if-present + + - name: Run Test + run: ${{ inputs.test }} + + - name: Code Coverage + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/node-test-parallel.yml b/.github/workflows/node-test-parallel.yml new file mode 100644 index 0000000..9658900 --- /dev/null +++ b/.github/workflows/node-test-parallel.yml @@ -0,0 +1,141 @@ +name: Node.js Unit Test in Parallel + +on: + workflow_call: + secrets: + CODECOV_TOKEN: + description: 'codecov token' + required: false + + inputs: + os: + type: string + description: 'Operator System, such as: ubuntu-latest, macos-latest' + default: 'ubuntu-latest, macos-latest, windows-latest' + + version: + type: string + description: 'Node.js Version, such as 18, 20, 22' + default: '18, 20, 22' + + install: + type: string + description: 'Install dependencies script' + default: 'npm i --no-package-lock --no-fund' + + test: + type: string + description: 'test script, such as: npm test, npm run ci' + default: 'npm run ci' + + action_ref: + type: string + description: 'Branch name for node-modules/github-actions, for test purpose' + default: master + + parallel: + type: number + description: 'Number of parallel test jobs' + default: 3 + +jobs: + Setup: + runs-on: ubuntu-latest + outputs: + os: ${{ steps.handler.outputs.os }} + version: ${{ steps.handler.outputs.version }} + node_index: ${{ steps.handler.outputs.node_index }} + total_nodes: ${{ steps.handler.outputs.total_nodes }} + + steps: + # Checkout action repository + - name: Checkout + uses: actions/checkout@v4 + with: + repository: node-modules/github-actions + path: action_repo + ref: ${{ inputs.action_ref }} + + # Setup Node.js environment + - name: Setup Node.js + uses: actions/setup-node@v4 + + # Install dependencies + - name: Install dependencies + run: npm i --no-package-lock --no-fund + working-directory: action_repo/scripts/test + + # Normalize inputs style + - name: Convert Inputs to Matrix + id: handler + run: node action_repo/scripts/test/index.js + env: + INPUT_OS: ${{ inputs.os }} + INPUT_VERSION: ${{ inputs.version }} + INPUT_PARALLEL: ${{ inputs.parallel }} + + Test: + needs: Setup + strategy: + fail-fast: false + matrix: + os: ${{ fromJSON(needs.setup.outputs.os) }} + version: ${{ fromJSON(needs.setup.outputs.version) }} + node_index: ${{ fromJSON(needs.setup.outputs.node_index) }} + total_nodes: ${{ fromJSON(needs.setup.outputs.total_nodes) }} + + name: Test (${{ matrix.os }}, ${{ matrix.version }}, ${{ matrix.node_index }}:${{ matrix.total_nodes }}) + runs-on: ${{ matrix.os }} + + concurrency: + group: ${{ github.workflow }}-#${{ github.event.pull_request.number || github.ref }}-(${{ matrix.os }}, ${{ matrix.version }}, ${{ matrix.node_index }} / ${{ matrix.total_nodes }}) + cancel-in-progress: true + + steps: + - name: Checkout Git Source + uses: actions/checkout@v4 + + - name: Calculate Architecture + uses: actions/github-script@v7 + id: calculate_architecture + with: + result-encoding: string + script: | + const osVersion = '${{ matrix.os }}'; + const isMacOS = osVersion === 'macos-latest' || osVersion.startsWith('macos'); + const nodeVersion = parseInt('${{ matrix.version }}'.split('.')[0]); + if (isMacOS && nodeVersion <= 14) { + return 'x64'; + } else { + return ''; + } + + - name: Use Node.js ${{ matrix.version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.version }} + architecture: ${{ steps.calculate_architecture.outputs.result }} + check-latest: true + + - name: Install Dependencies + run: ${{ inputs.install }} + env: + CI_NODE_INDEX: ${{ matrix.node_index }} + CI_NODE_TOTAL: ${{ matrix.total_nodes }} + + - name: Run Lint + run: npm run lint --if-present + env: + CI_NODE_INDEX: ${{ matrix.node_index }} + CI_NODE_TOTAL: ${{ matrix.total_nodes }} + + - name: Run Test + run: ${{ inputs.test }} + env: + CI_NODE_INDEX: ${{ matrix.node_index }} + CI_NODE_TOTAL: ${{ matrix.total_nodes }} + + - name: Code Coverage + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/node-test.yml b/.github/workflows/node-test.yml index 632ae72..5834c6c 100644 --- a/.github/workflows/node-test.yml +++ b/.github/workflows/node-test.yml @@ -2,25 +2,35 @@ name: Node.js Unit Test on: workflow_call: + secrets: + CODECOV_TOKEN: + description: 'codecov token' + required: false + inputs: os: type: string - description: 'Operator System, such as: ubuntu-latest,macos-latest' + description: 'Operator System, such as: ubuntu-latest, macos-latest' default: 'ubuntu-latest, macos-latest, windows-latest' version: type: string - description: 'Node.js Version, such as 16, 18' - default: '16, 18' + description: 'Node.js Version, such as 18, 20, 22' + default: '18, 20, 22' install: type: string description: 'Install dependencies script' default: 'npm i --no-package-lock --no-fund' + test: + type: string + description: 'test script, such as: npm test, npm run ci' + default: 'npm run ci' + action_ref: type: string - description: 'Branch name for artusjs/github-actions, for test purpose' + description: 'Branch name for node-modules/github-actions, for test purpose' default: master jobs: @@ -33,15 +43,15 @@ jobs: steps: # Checkout action repository - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: - repository: artusjs/github-actions + repository: node-modules/github-actions path: action_repo ref: ${{ inputs.action_ref }} # Setup Node.js environment - name: Setup Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 # Install dependencies - name: Install dependencies @@ -73,21 +83,38 @@ jobs: steps: - name: Checkout Git Source - uses: actions/checkout@v3 + uses: actions/checkout@v4 + + - name: Calculate Architecture + uses: actions/github-script@v7 + id: calculate_architecture + with: + result-encoding: string + script: | + const osVersion = '${{ matrix.os }}'; + const isMacOS = osVersion === 'macos-latest' || osVersion.startsWith('macos'); + const nodeVersion = parseInt('${{ matrix.version }}'.split('.')[0]); + if (isMacOS && nodeVersion <= 14) { + return 'x64'; + } else { + return ''; + } - name: Use Node.js ${{ matrix.version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.version }} + architecture: ${{ steps.calculate_architecture.outputs.result }} + check-latest: true - name: Install Dependencies run: ${{ inputs.install }} - name: Run Lint - run: npm run lint + run: npm run lint --if-present - name: Run Test - run: npm run ci + run: ${{ inputs.test }} - name: Code Coverage uses: codecov/codecov-action@v3 diff --git a/.github/workflows/npm-release.yml b/.github/workflows/npm-release.yml new file mode 100644 index 0000000..8539c43 --- /dev/null +++ b/.github/workflows/npm-release.yml @@ -0,0 +1,101 @@ +name: NPM Trusted Publisher + +on: + workflow_call: + secrets: + GIT_TOKEN: + description: 'github personal token' + required: true + + inputs: + checkTest: + type: boolean + description: whether run test before release + default: false + + dryRun: + type: boolean + description: pass dry-run to semantic-release + default: false + + install: + type: string + description: 'Install dependencies script' + default: 'npm i --no-package-lock --no-fund --force && rm -rf package-lock.json' + + action_ref: + type: string + description: 'Branch name for node-modules/github-actions, for test purpose' + default: master + +jobs: + Release: + permissions: + contents: write + id-token: write # Required for OIDC + deployments: write + issues: write + pull-requests: write + runs-on: ubuntu-latest + defaults: + run: + working-directory: main_repo + + concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + + steps: + # Checkout action repository + - name: Checkout action repository + uses: actions/checkout@v4 + with: + repository: node-modules/github-actions + path: action_repo + ref: ${{ inputs.action_ref }} + + # Checkout project repository + - name: Checkout project repository + uses: actions/checkout@v4 + with: + path: main_repo + token: ${{ secrets.GIT_TOKEN }} + + # Setup Node.js environment + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: lts/* + + # Ensure npm 11.5.1 or later is installed + - name: Update npm + run: npm install -g npm@latest + + # Install action dependencies + - name: Install action dependencies + run: npm i --no-package-lock --no-fund --force --omit=dev + working-directory: action_repo/scripts/npm-release + + # Install dependencies + - name: Install project dependencies + run: ${{ inputs.install }} + + # Run Test Only + - name: Run Test + run: npm test + if: inputs.checkTest + + - name: Semantic Release + id: release + run: node ../action_repo/scripts/npm-release/index.js + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DRYRUN: ${{ inputs.dryRun }} + + - name: Publish ${{ steps.release.outputs.name }}@${{ steps.release.outputs.release_version }} + if: steps.release.outputs.release_version && !inputs.dryRun + run: | + echo ${{ steps.release.outputs.name }} + echo ${{ steps.release.outputs.release_version }} + echo ${{ steps.release.outputs.registry }} + echo ${{ steps.release.outputs.cnpm_sync_url }} diff --git a/LICENSE b/LICENSE index 23ce342..fa05813 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ MIT License Copyright (c) 2022 Artus.js Working Group +Copyright (c) 2023 - present node-modules and other contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 26deb3b..1a6fe92 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# artusjs/github-actions +# node-modules/github-actions 为开源项目提供常见的可复用的 [GitHub Actions Workflow](https://docs.github.com/en/actions/using-workflows/reusing-workflows#using-inputs-and-secrets-in-a-reusable-workflow)。 @@ -12,8 +12,7 @@ 自动跑 Lint 和 Cov 单测 -> 参考示例:https://github.com/artus-cli/examples/actions - +> 参考示例: - 配置 `npm scripts`: @@ -36,23 +35,65 @@ name: CI on: push: branches: [ master, main ] - pull_request: branches: [ master, main, next, beta, '*.x' ] - schedule: - - cron: '0 2 * * *' - - workflow_dispatch: {} - jobs: Job: name: Node.js - uses: artusjs/github-actions/.github/workflows/node-test.yml@v1 + uses: node-modules/github-actions/.github/workflows/node-test.yml@master # 支持以下自定义配置,一般用默认值即可 # with: # os: 'ubuntu-latest, macos-latest, windows-latest' - # version: '16, 18' + # version: '18, 20, 22' + # test: 'npm run ci' + # secrets: + # CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} +``` + +### 开启 MySQL 和 Redis 服务依赖 + +```yaml +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + Job: + name: Node.js + uses: node-modules/github-actions/.github/workflows/node-test-mysql.yml@master + # with: + # os: 'ubuntu-latest' + # version: '18, 20, 22' + # secrets: + # CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} +``` + +### 开启并行测试 + +```yaml +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + Job: + name: Node.js + uses: node-modules/github-actions/.github/workflows/node-test-parallel.yml@master + # with: + # os: 'ubuntu-latest' + # version: '18, 20, 22' + # parallel: 3 + # secrets: + # CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} ``` ## 发布 NPM 包 @@ -75,30 +116,41 @@ jobs: ### 版本号规则 根据 Commit Message 自动计算下一个版本号: - - major 大版本:`BREAKING CHANGE` - - minor 特性版本: `feat:` 等 - - patch 补丁版本:`fix:` 等 - - 不发布版本: `chore:` / `docs:` / `style:` 等 - - 详见:https://github.com/semantic-release/commit-analyzer + +- major 大版本:`BREAKING CHANGE:`,必须加到 commit body 里面而不是第一行标题,否则不生效 + +```bash +perf(pencil): remove graphiteWidth option + +BREAKING CHANGE: The graphiteWidth option has been removed. +The default graphite width of 10mm is always used for performance reason. +``` + +```bash +feat: support WebStream + +BREAKING CHANGE: Drop Node.js < 18 support +``` + +- minor 特性版本: `feat:` 等 +- patch 补丁版本:`fix:` / `Revert` 等 +- 不发布版本: `chore:` / `docs:` / `style:` 等 +- 详见: **注意:** - - 不支持发布 0.x 版本,master 首次发布将是 1.0.0 版本 - - 如果你不期望直接发布,请在 beta 分支提交代码运行,将发布 `1.0.0-beta.1` 版本 - - 多版本发布实践参见 [semantic-release](https://semantic-release.gitbook.io/semantic-release/recipes/release-workflow/distribution-channels) 文档 +- 不支持发布 0.x 版本,master 首次发布将是 1.0.0 版本 +- 如果你不期望直接发布,请在 `beta` 分支提交代码运行,将发布 `1.0.0-beta.1` 版本 +- 多版本发布实践参见 [semantic-release](https://semantic-release.gitbook.io/semantic-release/recipes/release-workflow/distribution-channels) 文档 ### 配置方式 -- 创建 NPM Token - - NPM Registry 需创建 Automation Token,参见[文档](https://docs.npmjs.com/creating-and-viewing-access-tokens) - - GitHub Package 无需创建,默认支持 - - 创建 GitHub Token - - 因为生成的 CHANGELOG.md 和 package.json 需回写 GitHub,而默认的 `GITHUB_TOKEN` 没有该权限 + - 因为生成的 CHANGELOG.md 和 package.json 需回写 GitHub,而默认的 `GITHUB_TOKEN` 没有该权限。如会被保护分支规则拦截。 - 因此需要创建一个新的 Token,参见[文档](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) - 配置 Token - - 在项目或组织维度配置 2 个 `secrets`:`NPM_TOKEN` 和 `GIT_TOKEN` + - 在项目或组织维度配置 `GIT_TOKEN` - 参见[文档](https://docs.github.com/en/codespaces/managing-codespaces-for-your-organization/managing-encrypted-secrets-for-your-repository-and-organization-for-github-codespaces) - 创建 `.github/workflows/release.yml`: @@ -109,16 +161,14 @@ on: # 合并后自动发布 push: branches: [ master, main, next, beta, '*.x' ] - # 手动发布 - workflow_dispatch: {} + # workflow_dispatch: {} jobs: release: - name: Node.js - uses: artusjs/github-actions/.github/workflows/node-release.yml@v1 + name: NPM + uses: node-modules/github-actions/.github/workflows/npm-release.yml@master secrets: - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} GIT_TOKEN: ${{ secrets.GIT_TOKEN }} # with: # checkTest: false @@ -127,13 +177,6 @@ jobs: ### 发布到 GitHub Package -修改 `release.yml` 的 secrets: - -```yaml -secrets: - NPM_TOKEN: ${{ secrets.GITHUB_TOKEN }} -``` - 修改 `package.json`: ```json diff --git a/scripts/npm-release/index.js b/scripts/npm-release/index.js new file mode 100644 index 0000000..f5707ca --- /dev/null +++ b/scripts/npm-release/index.js @@ -0,0 +1,68 @@ +const path = require('path'); +const fs = require('fs'); +const core = require('@actions/core'); +const semanticRelease = require('semantic-release').default; +const { request } = require('undici'); + +async function run() { + const mainRepoPath = process.cwd(); + const pkgInfo = require(`${mainRepoPath}/package.json`); + const registry = pkgInfo.publishConfig?.registry || 'https://registry.npmjs.org'; + core.setOutput('name', pkgInfo.name); + core.setOutput('registry', registry); + + try { + const configFiles = [ + path.join(__dirname, 'release.config.js'), + path.join(mainRepoPath, 'release.config.js'), + ].filter(file => fs.existsSync(file)); + + core.info(`Using config files: ${configFiles.join(', ')}`); + + const result = await semanticRelease({ + dryRun: process.env.DRYRUN === 'true', + extends: configFiles, + }); + + const { nextRelease, lastRelease } = result; + + if (!nextRelease) { + core.notice('No release need to be published.'); + core.summary.addRaw('No release need to be published.'); + await core.summary.write(); + } else { + core.info(`Published release: ${nextRelease.version}`); + core.setOutput('release_version', nextRelease.version); + + // cnpm sync + try { + const res = await request(`https://registry-direct.npmmirror.com/-/package/${pkgInfo.name}/syncs`, { + method: 'PUT', + timeout: 30000, + }); + const { id } = await res.body.json(); + const logUrl = `https://registry.npmmirror.com/-/package/${pkgInfo.name}/syncs/${id}/log`; + core.setOutput('cnpm_sync_url', logUrl); + core.info(`cnpm sync log url: ${logUrl}`); + + // write summary + core.summary.addRaw(`## [${pkgInfo.name}](https://github.com/${process.env.GITHUB_REPOSITORY})\n`); + core.summary.addRaw(`- Release: ${lastRelease?.version ?? ''} -> ${nextRelease.version}\n`); + core.summary.addRaw(`- Registry: ${registry}\n`); + core.summary.addRaw(`- CNPM Sync: ${logUrl}\n`); + core.summary.addRaw(`- DryRun: ${process.env.DRYRUN}\n`); + } catch (err) { + core.info(`cnpm sync ${pkgInfo.name} fail, ${err.message}`); + core.summary.addRaw(`- CNPM Sync ${pkgInfo.name} error: ${err.message}\n`); + } + core.summary.addRaw(nextRelease.notes); + await core.summary.write(); + } + console.log('Result:', result); + } catch (error) { + console.error(error); + core.setFailed(error); + } +} + +run(); diff --git a/scripts/npm-release/package.json b/scripts/npm-release/package.json new file mode 100644 index 0000000..2f2e5eb --- /dev/null +++ b/scripts/npm-release/package.json @@ -0,0 +1,21 @@ +{ + "name": "ci-release", + "dependencies": { + "@actions/core": "^1.10.0", + "@actions/exec": "^1.1.1", + "@semantic-release/npm": "13.0.0-alpha.5", + "@semantic-release/changelog": "^6.0.3", + "@semantic-release/exec": "^7.1.0", + "@semantic-release/git": "^10.0.1", + "@semantic-release/commit-analyzer": "^13.0.1", + "@semantic-release/release-notes-generator": "^14.0.3", + "@semantic-release/github": "^11.0.3", + "conventional-changelog-conventionalcommits": "^5.0.0", + "semantic-release": "25.0.0-alpha.4", + "undici": "^5.14.0" + }, + "devDependencies": { + "@types/node": "24", + "@types/semantic-release": "21" + } +} diff --git a/scripts/npm-release/release.config.js b/scripts/npm-release/release.config.js new file mode 100644 index 0000000..77abc06 --- /dev/null +++ b/scripts/npm-release/release.config.js @@ -0,0 +1,20 @@ +module.exports = { + plugins: [ + [ '@semantic-release/commit-analyzer', { preset: 'conventionalcommits' } ], + [ '@semantic-release/release-notes-generator', { preset: 'conventionalcommits' } ], + [ '@semantic-release/changelog', { changelogTitle: '# Changelog' } ], + [ '@semantic-release/npm', {} ], + + [ '@semantic-release/git', + { + message: 'Release <%= nextRelease.version %>\n\n[skip ci]\n\n<%= nextRelease.notes %>', + }, + ], + + [ '@semantic-release/github', + { + addReleases: 'bottom', + }, + ], + ], +}; diff --git a/scripts/release/index.js b/scripts/release/index.js index 0410e58..a19b1f2 100644 --- a/scripts/release/index.js +++ b/scripts/release/index.js @@ -1,15 +1,9 @@ const path = require('path'); const fs = require('fs'); const core = require('@actions/core'); -const { getExecOutput } = require('@actions/exec'); const semanticRelease = require('semantic-release'); const { request } = require('undici'); -async function execGit(cmd) { - const { stdout } = await getExecOutput(cmd); - return stdout.trim(); -} - async function run() { const mainRepoPath = process.cwd(); const pkgInfo = require(`${mainRepoPath}/package.json`); @@ -17,8 +11,6 @@ async function run() { core.setOutput('name', pkgInfo.name); core.setOutput('registry', registry); - const lastCommitId = await execGit(`git log -n1 --format="%h"`); - try { const configFiles = [ path.join(__dirname, 'release.config.js'), @@ -43,34 +35,32 @@ async function run() { core.setOutput('release_version', nextRelease.version); // cnpm sync - const res = await request(`https://registry-direct.npmmirror.com/-/package/${pkgInfo.name}/syncs`, { method: 'PUT' }); - const { id } = await res.body.json(); - const logUrl = `https://registry.npmmirror.com/-/package/${pkgInfo.name}/syncs/${id}/log`; - core.setOutput('cnpm_sync_url', logUrl); - core.info(`cnpm sync log url: ${logUrl}`); + try { + const res = await request(`https://registry-direct.npmmirror.com/-/package/${pkgInfo.name}/syncs`, { + method: 'PUT', + timeout: 30000, + }); + const { id } = await res.body.json(); + const logUrl = `https://registry.npmmirror.com/-/package/${pkgInfo.name}/syncs/${id}/log`; + core.setOutput('cnpm_sync_url', logUrl); + core.info(`cnpm sync log url: ${logUrl}`); - // write summary - core.summary.addRaw(`## [${pkgInfo.name}](https://github.com/${process.env.GITHUB_REPOSITORY})\n`); - core.summary.addRaw(`- Release: ${lastRelease?.version ?? ''} -> ${nextRelease.version}\n`); - core.summary.addRaw(`- Registry: ${registry}\n`); - core.summary.addRaw(`- CNPM Sync: ${logUrl}\n`); - core.summary.addRaw(`- DryRun: ${process.env.DRYRUN}\n`); + // write summary + core.summary.addRaw(`## [${pkgInfo.name}](https://github.com/${process.env.GITHUB_REPOSITORY})\n`); + core.summary.addRaw(`- Release: ${lastRelease?.version ?? ''} -> ${nextRelease.version}\n`); + core.summary.addRaw(`- Registry: ${registry}\n`); + core.summary.addRaw(`- CNPM Sync: ${logUrl}\n`); + core.summary.addRaw(`- DryRun: ${process.env.DRYRUN}\n`); + } catch (err) { + core.info(`cnpm sync ${pkgInfo.name} fail, ${err.message}`); + core.summary.addRaw(`- CNPM Sync ${pkgInfo.name} error: ${err.message}\n`); + } core.summary.addRaw(nextRelease.notes); await core.summary.write(); } console.log('Result:', result); } catch (error) { - console.error('> Rollback to last commit'); - const currentCommitId = await execGit(`git log -n1 --format="%h"`); - const tagId = await execGit(`git tag --contains ${currentCommitId}`); - - await execGit(`git push --delete origin ${tagId}`); - await execGit(`git reset --hard ${lastCommitId}`); - await execGit(`git push --force`); - - console.error('> Rollback finished'); - - // console.error(error); + console.error(error); core.setFailed(error); } } diff --git a/scripts/test/index.js b/scripts/test/index.js index 1becf7b..ad5060b 100644 --- a/scripts/test/index.js +++ b/scripts/test/index.js @@ -2,8 +2,20 @@ const core = require('@actions/core'); const os = core.getInput('os').split(',').map(x => x.trim()); const version = core.getInput('version').split(',').map(x => x.trim()); +const mysqlVersionInput = core.getInput('mysql_version') || '5'; +const mysqlVersion = mysqlVersionInput.split(',').map(x => x.trim()); + +const parallel = parseInt(core.getInput('parallel')) || 3; +const node_index = []; +const total_nodes = [ parallel ]; +for (let i = 0; i < parallel; i++) { + node_index.push(i); +} core.setOutput('os', JSON.stringify(os)); core.setOutput('version', JSON.stringify(version)); +core.setOutput('mysql_version', JSON.stringify(mysqlVersion === '' ? [] : mysqlVersion)); +core.setOutput('node_index', JSON.stringify(node_index)); +core.setOutput('total_nodes', JSON.stringify(total_nodes)); -core.info(`os: ${os}, version: ${version}`); +core.info(`[debug] os: ${JSON.stringify(os)}, version: ${JSON.stringify(version)}, mysql_version: ${JSON.stringify(mysqlVersion)}, parallel: ${parallel}, node_index: ${JSON.stringify(node_index)}, total_nodes: ${JSON.stringify(total_nodes)}`);