diff --git a/.eslintrc.js b/.eslintrc.js index 5db9f815..f21d26ec 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -10,6 +10,9 @@ const localConfigs = readdir(__dirname) module.exports = { root: true, + ignorePatterns: [ + 'tap-testdir*/', + ], extends: [ '@npmcli', ...localConfigs, diff --git a/.github/actions/create-check/action.yml b/.github/actions/create-check/action.yml new file mode 100644 index 00000000..0e7d6ce0 --- /dev/null +++ b/.github/actions/create-check/action.yml @@ -0,0 +1,52 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: 'Create Check' +inputs: + name: + required: true + token: + required: true + sha: + required: true + check-name: + default: '' +outputs: + check-id: + value: ${{ steps.create-check.outputs.check_id }} +runs: + using: "composite" + steps: + - name: Get Workflow Job + uses: actions/github-script@v6 + id: workflow + env: + JOB_NAME: "${{ inputs.name }}" + SHA: "${{ inputs.sha }}" + with: + result-encoding: string + script: | + const { repo: { owner, repo}, runId, serverUrl } = context + const { JOB_NAME, SHA } = process.env + + const job = await github.rest.actions.listJobsForWorkflowRun({ + owner, + repo, + run_id: runId, + per_page: 100 + }).then(r => r.data.jobs.find(j => j.name.endsWith(JOB_NAME))) + + return [ + `This check is assosciated with ${serverUrl}/${owner}/${repo}/commit/${SHA}.`, + 'Run logs:', + job?.html_url || `could not be found for a job ending with: "${JOB_NAME}"`, + ].join(' ') + - name: Create Check + uses: LouisBrunner/checks-action@v1.6.0 + id: create-check + with: + token: ${{ inputs.token }} + sha: ${{ inputs.sha }} + status: in_progress + name: ${{ inputs.check-name || inputs.name }} + output: | + {"summary":"${{ steps.workflow.outputs.result }}"} diff --git a/.github/actions/install-latest-npm/action.yml b/.github/actions/install-latest-npm/action.yml new file mode 100644 index 00000000..8339dbf0 --- /dev/null +++ b/.github/actions/install-latest-npm/action.yml @@ -0,0 +1,58 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: 'Install Latest npm' +description: 'Install the latest version of npm compatible with the Node version' +inputs: + node: + description: 'Current Node version' + required: true +runs: + using: "composite" + steps: + # node 10/12/14 ship with npm@6, which is known to fail when updating itself in windows + - name: Update Windows npm + if: | + runner.os == 'Windows' && ( + startsWith(inputs.node, 'v10.') || + startsWith(inputs.node, 'v12.') || + startsWith(inputs.node, 'v14.') + ) + shell: cmd + run: | + curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz + tar xf npm-7.5.4.tgz + cd package + node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz + cd .. + rmdir /s /q package + - name: Install Latest npm + shell: bash + env: + NODE_VERSION: ${{ inputs.node }} + working-directory: ${{ runner.temp }} + run: | + MATCH="" + SPECS=("latest" "next-10" "next-9" "next-8" "next-7" "next-6") + + echo "node@$NODE_VERSION" + + for SPEC in ${SPECS[@]}; do + ENGINES=$(npm view npm@$SPEC --json | jq -r '.engines.node') + echo "Checking if node@$NODE_VERSION satisfies npm@$SPEC ($ENGINES)" + + if npx semver -r "$ENGINES" "$NODE_VERSION" > /dev/null; then + MATCH=$SPEC + echo "Found compatible version: npm@$MATCH" + break + fi + done + + if [ -z $MATCH ]; then + echo "Could not find a compatible version of npm for node@$NODE_VERSION" + exit 1 + fi + + npm i --prefer-online --no-fund --no-audit -g npm@$MATCH + - name: npm Version + shell: bash + run: npm -v diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 8da2a452..d735ccf2 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,6 +7,7 @@ updates: directory: / schedule: interval: daily + target-branch: "main" allow: - dependency-type: direct versioning-strategy: increase-if-necessary @@ -15,3 +16,38 @@ updates: prefix-development: chore labels: - "Dependencies" + open-pull-requests-limit: 10 + - package-ecosystem: npm + directory: / + schedule: + interval: daily + target-branch: "release/v5" + allow: + - dependency-type: direct + dependency-name: "@npmcli/template-oss" + versioning-strategy: increase-if-necessary + commit-message: + prefix: deps + prefix-development: chore + labels: + - "Dependencies" + - "Backport" + - "release/v5" + open-pull-requests-limit: 10 + - package-ecosystem: npm + directory: / + schedule: + interval: daily + target-branch: "release/v6" + allow: + - dependency-type: direct + dependency-name: "@npmcli/template-oss" + versioning-strategy: increase-if-necessary + commit-message: + prefix: deps + prefix-development: chore + labels: + - "Dependencies" + - "Backport" + - "release/v6" + open-pull-requests-limit: 10 diff --git a/.github/settings.yml b/.github/settings.yml index adbef7e6..206b6eeb 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -15,6 +15,7 @@ branches: protection: required_status_checks: null enforce_admins: true + block_creations: true required_pull_request_reviews: required_approving_review_count: 1 require_code_owner_reviews: true @@ -24,10 +25,11 @@ branches: apps: [] users: [] teams: [ "cli-team" ] - - name: latest + - name: release/v5 protection: required_status_checks: null enforce_admins: true + block_creations: true required_pull_request_reviews: required_approving_review_count: 1 require_code_owner_reviews: true @@ -37,10 +39,11 @@ branches: apps: [] users: [] teams: [ "cli-team" ] - - name: release/v* + - name: release/v6 protection: required_status_checks: null enforce_admins: true + block_creations: true required_pull_request_reviews: required_approving_review_count: 1 require_code_owner_reviews: true diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 8b8f3748..fa3163a8 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -25,12 +25,14 @@ jobs: git config --global user.name "npm CLI robot" - name: Setup Node uses: actions/setup-node@v3 + id: node with: - node-version: 18.x - - name: Install npm@8 - run: npm i --prefer-online --no-fund --no-audit -g npm@8 - - name: npm Version - run: npm -v + node-version: 20.x + check-latest: contains('20.x', '.x') + - name: Install Latest npm + uses: ./.github/actions/install-latest-npm + with: + node: ${{ steps.node.outputs.node-version }} - name: Install Dependencies run: npm i --ignore-scripts --no-audit --no-fund --package-lock - name: Run Production Audit diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index 98b70866..9f9c2a2a 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -27,49 +27,6 @@ jobs: run: shell: bash steps: - - name: Get Workflow Job - uses: actions/github-script@v6 - if: inputs.check-sha - id: check-output - env: - JOB_NAME: "Lint All" - MATRIX_NAME: "" - with: - script: | - const { owner, repo } = context.repo - - const { data } = await github.rest.actions.listJobsForWorkflowRun({ - owner, - repo, - run_id: context.runId, - per_page: 100 - }) - - const jobName = process.env.JOB_NAME + process.env.MATRIX_NAME - const job = data.jobs.find(j => j.name.endsWith(jobName)) - const jobUrl = job?.html_url - - const shaUrl = `${context.serverUrl}/${owner}/${repo}/commit/${{ inputs.check-sha }}` - - let summary = `This check is assosciated with ${shaUrl}\n\n` - - if (jobUrl) { - summary += `For run logs, click here: ${jobUrl}` - } else { - summary += `Run logs could not be found for a job with name: "${jobName}"` - } - - return { summary } - - name: Create Check - uses: LouisBrunner/checks-action@v1.6.0 - id: check - if: inputs.check-sha - with: - token: ${{ secrets.GITHUB_TOKEN }} - status: in_progress - name: Lint All - sha: ${{ inputs.check-sha }} - output: ${{ steps.check-output.outputs.result }} - name: Checkout uses: actions/checkout@v3 with: @@ -78,14 +35,24 @@ jobs: run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" + - name: Create Check + id: create-check + if: ${{ inputs.check-sha }} + uses: ./.github/actions/create-check + with: + name: "Lint All" + token: ${{ secrets.GITHUB_TOKEN }} + sha: ${{ inputs.check-sha }} - name: Setup Node uses: actions/setup-node@v3 + id: node with: - node-version: 18.x - - name: Install npm@8 - run: npm i --prefer-online --no-fund --no-audit -g npm@8 - - name: npm Version - run: npm -v + node-version: 20.x + check-latest: contains('20.x', '.x') + - name: Install Latest npm + uses: ./.github/actions/install-latest-npm + with: + node: ${{ steps.node.outputs.node-version }} - name: Install Dependencies run: npm i --ignore-scripts --no-audit --no-fund - name: Lint @@ -94,11 +61,11 @@ jobs: run: npm run postlint --ignore-scripts - name: Conclude Check uses: LouisBrunner/checks-action@v1.6.0 - if: steps.check.outputs.check_id && always() + if: always() with: token: ${{ secrets.GITHUB_TOKEN }} conclusion: ${{ job.status }} - check_id: ${{ steps.check.outputs.check_id }} + check_id: ${{ steps.create-check.outputs.check-id }} test-all: name: Test All - ${{ matrix.platform.name }} - ${{ matrix.node-version }} @@ -123,54 +90,12 @@ jobs: - 14.x - 16.x - 18.x + - 20.x runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - - name: Get Workflow Job - uses: actions/github-script@v6 - if: inputs.check-sha - id: check-output - env: - JOB_NAME: "Test All" - MATRIX_NAME: " - ${{ matrix.platform.name }} - ${{ matrix.node-version }}" - with: - script: | - const { owner, repo } = context.repo - - const { data } = await github.rest.actions.listJobsForWorkflowRun({ - owner, - repo, - run_id: context.runId, - per_page: 100 - }) - - const jobName = process.env.JOB_NAME + process.env.MATRIX_NAME - const job = data.jobs.find(j => j.name.endsWith(jobName)) - const jobUrl = job?.html_url - - const shaUrl = `${context.serverUrl}/${owner}/${repo}/commit/${{ inputs.check-sha }}` - - let summary = `This check is assosciated with ${shaUrl}\n\n` - - if (jobUrl) { - summary += `For run logs, click here: ${jobUrl}` - } else { - summary += `Run logs could not be found for a job with name: "${jobName}"` - } - - return { summary } - - name: Create Check - uses: LouisBrunner/checks-action@v1.6.0 - id: check - if: inputs.check-sha - with: - token: ${{ secrets.GITHUB_TOKEN }} - status: in_progress - name: Test All - ${{ matrix.platform.name }} - ${{ matrix.node-version }} - sha: ${{ inputs.check-sha }} - output: ${{ steps.check-output.outputs.result }} - name: Checkout uses: actions/checkout@v3 with: @@ -179,28 +104,24 @@ jobs: run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" + - name: Create Check + id: create-check + if: ${{ inputs.check-sha }} + uses: ./.github/actions/create-check + with: + name: "Test All - ${{ matrix.platform.name }} - ${{ matrix.node-version }}" + token: ${{ secrets.GITHUB_TOKEN }} + sha: ${{ inputs.check-sha }} - name: Setup Node uses: actions/setup-node@v3 + id: node with: node-version: ${{ matrix.node-version }} - - name: Update Windows npm - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - name: Install npm@7 - if: startsWith(matrix.node-version, '10.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Install npm@8 - if: ${{ !startsWith(matrix.node-version, '10.') }} - run: npm i --prefer-online --no-fund --no-audit -g npm@8 - - name: npm Version - run: npm -v + check-latest: contains(matrix.node-version, '.x') + - name: Install Latest npm + uses: ./.github/actions/install-latest-npm + with: + node: ${{ steps.node.outputs.node-version }} - name: Install Dependencies run: npm i --ignore-scripts --no-audit --no-fund - name: Add Problem Matcher @@ -209,8 +130,8 @@ jobs: run: npm test --ignore-scripts - name: Conclude Check uses: LouisBrunner/checks-action@v1.6.0 - if: steps.check.outputs.check_id && always() + if: always() with: token: ${{ secrets.GITHUB_TOKEN }} conclusion: ${{ job.status }} - check_id: ${{ steps.check.outputs.check_id }} + check_id: ${{ steps.create-check.outputs.check-id }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb473086..f65f93a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,6 @@ on: push: branches: - main - - latest - release/v* schedule: # "At 09:00 UTC (02:00 PT) on Monday" https://crontab.guru/#0_9_*_*_1 @@ -31,12 +30,14 @@ jobs: git config --global user.name "npm CLI robot" - name: Setup Node uses: actions/setup-node@v3 + id: node with: - node-version: 18.x - - name: Install npm@8 - run: npm i --prefer-online --no-fund --no-audit -g npm@8 - - name: npm Version - run: npm -v + node-version: 20.x + check-latest: contains('20.x', '.x') + - name: Install Latest npm + uses: ./.github/actions/install-latest-npm + with: + node: ${{ steps.node.outputs.node-version }} - name: Install Dependencies run: npm i --ignore-scripts --no-audit --no-fund - name: Lint @@ -67,6 +68,7 @@ jobs: - 14.x - 16.x - 18.x + - 20.x runs-on: ${{ matrix.platform.os }} defaults: run: @@ -80,26 +82,14 @@ jobs: git config --global user.name "npm CLI robot" - name: Setup Node uses: actions/setup-node@v3 + id: node with: node-version: ${{ matrix.node-version }} - - name: Update Windows npm - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - name: Install npm@7 - if: startsWith(matrix.node-version, '10.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Install npm@8 - if: ${{ !startsWith(matrix.node-version, '10.') }} - run: npm i --prefer-online --no-fund --no-audit -g npm@8 - - name: npm Version - run: npm -v + check-latest: contains(matrix.node-version, '.x') + - name: Install Latest npm + uses: ./.github/actions/install-latest-npm + with: + node: ${{ steps.node.outputs.node-version }} - name: Install Dependencies run: npm i --ignore-scripts --no-audit --no-fund - name: Add Problem Matcher diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 21244879..9fb3f79a 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -6,12 +6,10 @@ on: push: branches: - main - - latest - release/v* pull_request: branches: - main - - latest - release/v* schedule: # "At 10:00 UTC (03:00 PT) on Monday" https://crontab.guru/#0_10_*_*_1 diff --git a/.github/workflows/post-dependabot.yml b/.github/workflows/post-dependabot.yml index 03c85681..11a7b7c8 100644 --- a/.github/workflows/post-dependabot.yml +++ b/.github/workflows/post-dependabot.yml @@ -26,12 +26,14 @@ jobs: git config --global user.name "npm CLI robot" - name: Setup Node uses: actions/setup-node@v3 + id: node with: - node-version: 18.x - - name: Install npm@8 - run: npm i --prefer-online --no-fund --no-audit -g npm@8 - - name: npm Version - run: npm -v + node-version: 20.x + check-latest: contains('20.x', '.x') + - name: Install Latest npm + uses: ./.github/actions/install-latest-npm + with: + node: ${{ steps.node.outputs.node-version }} - name: Install Dependencies run: npm i --ignore-scripts --no-audit --no-fund - name: Fetch Dependabot Metadata diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index da5779df..0b5789e0 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -29,22 +29,22 @@ jobs: git config --global user.name "npm CLI robot" - name: Setup Node uses: actions/setup-node@v3 + id: node with: - node-version: 18.x - - name: Install npm@8 - run: npm i --prefer-online --no-fund --no-audit -g npm@8 - - name: npm Version - run: npm -v + node-version: 20.x + check-latest: contains('20.x', '.x') + - name: Install Latest npm + uses: ./.github/actions/install-latest-npm + with: + node: ${{ steps.node.outputs.node-version }} - name: Install Dependencies run: npm i --ignore-scripts --no-audit --no-fund - name: Run Commitlint on Commits id: commit continue-on-error: true - run: | - npx --offline commitlint -V --from 'origin/${{ github.base_ref }}' --to ${{ github.event.pull_request.head.sha }} + run: npx --offline commitlint -V --from 'origin/${{ github.base_ref }}' --to ${{ github.event.pull_request.head.sha }} - name: Run Commitlint on PR Title if: steps.commit.outcome == 'failure' env: PR_TITLE: ${{ github.event.pull_request.title }} - run: | - echo '$PR_TITLE' | npx --offline commitlint -V + run: echo "$PR_TITLE" | npx --offline commitlint -V diff --git a/.github/workflows/release-integration.yml b/.github/workflows/release-integration.yml new file mode 100644 index 00000000..36637581 --- /dev/null +++ b/.github/workflows/release-integration.yml @@ -0,0 +1,76 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: Release Integration + +on: + workflow_dispatch: + inputs: + releases: + required: true + type: string + description: 'A json array of releases. Required fields: publish: tagName, publishTag. publish check: pkgName, version' + workflow_call: + inputs: + releases: + required: true + type: string + description: 'A json array of releases. Required fields: publish: tagName, publishTag. publish check: pkgName, version' + secrets: + PUBLISH_TOKEN: + required: true + +jobs: + publish: + name: Publish + runs-on: ubuntu-latest + defaults: + run: + shell: bash + permissions: + id-token: write + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + ref: ${{ fromJSON(inputs.releases)[0].tagName }} + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + id: node + with: + node-version: 20.x + check-latest: contains('20.x', '.x') + - name: Install Latest npm + uses: ./.github/actions/install-latest-npm + with: + node: ${{ steps.node.outputs.node-version }} + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund + - name: Set npm authToken + run: npm config set '//registry.npmjs.org/:_authToken'=\${PUBLISH_TOKEN} + - name: Publish + env: + PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} + run: | + EXIT_CODE=0 + + function each_release { + if npm publish --provenance --tag="$1"; then + echo 0 + else + echo 1 + fi + } + + for release in $(echo '${{ inputs.releases }}' | jq -r '.[] | @base64'); do + PUBLISH_TAG=$(echo "$release" | base64 --decode | jq -r .publishTag) + STATUS=$(each_release "$PUBLISH_TAG") + if [[ "$STATUS" -eq 1 ]]; then + EXIT_CODE=$STATUS + fi + done + + exit $EXIT_CODE diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b086b0a5..be675916 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,15 +3,9 @@ name: Release on: - workflow_dispatch: - inputs: - release-pr: - description: a release PR number to rerun release jobs on - type: string push: branches: - main - - latest - release/v* permissions: @@ -23,12 +17,12 @@ jobs: release: outputs: pr: ${{ steps.release.outputs.pr }} - release: ${{ steps.release.outputs.release }} - releases: ${{ steps.release.outputs.releases }} - branch: ${{ steps.release.outputs.pr-branch }} + pr-branch: ${{ steps.release.outputs.pr-branch }} pr-number: ${{ steps.release.outputs.pr-number }} - comment-id: ${{ steps.pr-comment.outputs.result }} - check-id: ${{ steps.check.outputs.check_id }} + pr-sha: ${{ steps.release.outputs.pr-sha }} + releases: ${{ steps.release.outputs.releases }} + comment-id: ${{ steps.create-comment.outputs.comment-id || steps.update-comment.outputs.comment-id }} + check-id: ${{ steps.create-check.outputs.check-id }} name: Release if: github.repository_owner == 'npm' runs-on: ubuntu-latest @@ -44,101 +38,68 @@ jobs: git config --global user.name "npm CLI robot" - name: Setup Node uses: actions/setup-node@v3 + id: node + with: + node-version: 20.x + check-latest: contains('20.x', '.x') + - name: Install Latest npm + uses: ./.github/actions/install-latest-npm with: - node-version: 18.x - - name: Install npm@8 - run: npm i --prefer-online --no-fund --no-audit -g npm@8 - - name: npm Version - run: npm -v + node: ${{ steps.node.outputs.node-version }} - name: Install Dependencies run: npm i --ignore-scripts --no-audit --no-fund - name: Release Please id: release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - npx --offline template-oss-release-please "${{ github.ref_name }}" "${{ inputs.release-pr }}" - - name: Post Pull Request Comment + run: npx --offline template-oss-release-please --branch="${{ github.ref_name }}" --backport="" --defaultTag="latest" + - name: Create Release Manager Comment Text if: steps.release.outputs.pr-number uses: actions/github-script@v6 - id: pr-comment - env: - PR_NUMBER: ${{ steps.release.outputs.pr-number }} - REF_NAME: ${{ github.ref_name }} + id: comment-text with: + result-encoding: string script: | - const { REF_NAME, PR_NUMBER: issue_number } = process.env const { runId, repo: { owner, repo } } = context - const { data: workflow } = await github.rest.actions.getWorkflowRun({ owner, repo, run_id: runId }) - - let body = '## Release Manager\n\n' - - const comments = await github.paginate(github.rest.issues.listComments, { owner, repo, issue_number }) - let commentId = comments.find(c => c.user.login === 'github-actions[bot]' && c.body.startsWith(body))?.id - - body += `Release workflow run: ${workflow.html_url}\n\n#### Force CI to Update This Release\n\n` - body += `This PR will be updated and CI will run for every non-\`chore:\` commit that is pushed to \`${REF_NAME}\`. ` - body += `To force CI to update this PR, run this command:\n\n` - body += `\`\`\`\ngh workflow run release.yml -r ${REF_NAME} -R ${owner}/${repo} -f release-pr=${issue_number}\n\`\`\`` - - if (commentId) { - await github.rest.issues.updateComment({ owner, repo, comment_id: commentId, body }) - } else { - const { data: comment } = await github.rest.issues.createComment({ owner, repo, issue_number, body }) - commentId = comment?.id - } - - return commentId - - name: Get Workflow Job - uses: actions/github-script@v6 - if: steps.release.outputs.pr-sha - id: check-output - env: - JOB_NAME: "Release" - MATRIX_NAME: "" + return['## Release Manager', `Release workflow run: ${workflow.html_url}`].join('\n\n') + - name: Find Release Manager Comment + uses: peter-evans/find-comment@v2 + if: steps.release.outputs.pr-number + id: found-comment with: - script: | - const { owner, repo } = context.repo - - const { data } = await github.rest.actions.listJobsForWorkflowRun({ - owner, - repo, - run_id: context.runId, - per_page: 100 - }) - - const jobName = process.env.JOB_NAME + process.env.MATRIX_NAME - const job = data.jobs.find(j => j.name.endsWith(jobName)) - const jobUrl = job?.html_url - - const shaUrl = `${context.serverUrl}/${owner}/${repo}/commit/${{ steps.release.outputs.pr-sha }}` - - let summary = `This check is assosciated with ${shaUrl}\n\n` - - if (jobUrl) { - summary += `For run logs, click here: ${jobUrl}` - } else { - summary += `Run logs could not be found for a job with name: "${jobName}"` - } - - return { summary } + issue-number: ${{ steps.release.outputs.pr-number }} + comment-author: 'github-actions[bot]' + body-includes: '## Release Manager' + - name: Create Release Manager Comment + id: create-comment + if: steps.release.outputs.pr-number && !steps.found-comment.outputs.comment-id + uses: peter-evans/create-or-update-comment@v3 + with: + issue-number: ${{ steps.release.outputs.pr-number }} + body: ${{ steps.comment-text.outputs.result }} + - name: Update Release Manager Comment + id: update-comment + if: steps.release.outputs.pr-number && steps.found-comment.outputs.comment-id + uses: peter-evans/create-or-update-comment@v3 + with: + comment-id: ${{ steps.found-comment.outputs.comment-id }} + body: ${{ steps.comment-text.outputs.result }} + edit-mode: 'replace' - name: Create Check - uses: LouisBrunner/checks-action@v1.6.0 - id: check + id: create-check + uses: ./.github/actions/create-check if: steps.release.outputs.pr-sha with: + name: "Release" token: ${{ secrets.GITHUB_TOKEN }} - status: in_progress - name: Release sha: ${{ steps.release.outputs.pr-sha }} - output: ${{ steps.check-output.outputs.result }} update: needs: release outputs: sha: ${{ steps.commit.outputs.sha }} - check-id: ${{ steps.check.outputs.check_id }} + check-id: ${{ steps.create-check.outputs.check-id }} name: Update - Release if: github.repository_owner == 'npm' && needs.release.outputs.pr runs-on: ubuntu-latest @@ -150,29 +111,38 @@ jobs: uses: actions/checkout@v3 with: fetch-depth: 0 - ref: ${{ needs.release.outputs.branch }} + ref: ${{ needs.release.outputs.pr-branch }} - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - name: Setup Node uses: actions/setup-node@v3 + id: node with: - node-version: 18.x - - name: Install npm@8 - run: npm i --prefer-online --no-fund --no-audit -g npm@8 - - name: npm Version - run: npm -v + node-version: 20.x + check-latest: contains('20.x', '.x') + - name: Install Latest npm + uses: ./.github/actions/install-latest-npm + with: + node: ${{ steps.node.outputs.node-version }} - name: Install Dependencies run: npm i --ignore-scripts --no-audit --no-fund + - name: Create Release Manager Checklist Text + id: comment-text + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: npm exec --offline -- template-oss-release-manager --pr="${{ needs.release.outputs.pr-number }}" --backport="" --defaultTag="latest" --publish + - name: Append Release Manager Comment + uses: peter-evans/create-or-update-comment@v3 + with: + comment-id: ${{ needs.release.outputs.comment-id }} + body: ${{ steps.comment-text.outputs.result }} + edit-mode: 'append' - name: Run Post Pull Request Actions env: - RELEASE_PR_NUMBER: ${{ needs.release.outputs.pr-number }} - RELEASE_COMMENT_ID: ${{ needs.release.outputs.comment-id }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - npm exec --offline -- template-oss-release-manager --lockfile=false --publish=true - npm run rp-pull-request --ignore-scripts --if-present + run: npm run rp-pull-request --ignore-scripts --if-present -- --pr="${{ needs.release.outputs.pr-number }}" --commentId="${{ needs.release.outputs.comment-id }}" - name: Commit id: commit env: @@ -181,52 +151,16 @@ jobs: git commit --all --amend --no-edit || true git push --force-with-lease echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT - - name: Get Workflow Job - uses: actions/github-script@v6 - if: steps.commit.outputs.sha - id: check-output - env: - JOB_NAME: "Update - Release" - MATRIX_NAME: "" - with: - script: | - const { owner, repo } = context.repo - - const { data } = await github.rest.actions.listJobsForWorkflowRun({ - owner, - repo, - run_id: context.runId, - per_page: 100 - }) - - const jobName = process.env.JOB_NAME + process.env.MATRIX_NAME - const job = data.jobs.find(j => j.name.endsWith(jobName)) - const jobUrl = job?.html_url - - const shaUrl = `${context.serverUrl}/${owner}/${repo}/commit/${{ steps.commit.outputs.sha }}` - - let summary = `This check is assosciated with ${shaUrl}\n\n` - - if (jobUrl) { - summary += `For run logs, click here: ${jobUrl}` - } else { - summary += `Run logs could not be found for a job with name: "${jobName}"` - } - - return { summary } - name: Create Check - uses: LouisBrunner/checks-action@v1.6.0 - id: check - if: steps.commit.outputs.sha + id: create-check + uses: ./.github/actions/create-check with: + name: "Update - Release" + check-name: "Release" token: ${{ secrets.GITHUB_TOKEN }} - status: in_progress - name: Release sha: ${{ steps.commit.outputs.sha }} - output: ${{ steps.check-output.outputs.result }} - name: Conclude Check uses: LouisBrunner/checks-action@v1.6.0 - if: needs.release.outputs.check-id && always() with: token: ${{ secrets.GITHUB_TOKEN }} conclusion: ${{ job.status }} @@ -238,7 +172,7 @@ jobs: if: needs.release.outputs.pr uses: ./.github/workflows/ci-release.yml with: - ref: ${{ needs.release.outputs.branch }} + ref: ${{ needs.release.outputs.pr-branch }} check-sha: ${{ needs.update.outputs.sha }} post-ci: @@ -250,8 +184,8 @@ jobs: run: shell: bash steps: - - name: Get Needs Result - id: needs-result + - name: Get CI Conclusion + id: conclusion run: | result="" if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then @@ -264,14 +198,15 @@ jobs: echo "result=$result" >> $GITHUB_OUTPUT - name: Conclude Check uses: LouisBrunner/checks-action@v1.6.0 - if: needs.update.outputs.check-id && always() with: token: ${{ secrets.GITHUB_TOKEN }} - conclusion: ${{ steps.needs-result.outputs.result }} + conclusion: ${{ steps.conclusion.outputs.result }} check_id: ${{ needs.update.outputs.check-id }} post-release: needs: release + outputs: + comment-id: ${{ steps.create-comment.outputs.comment-id }} name: Post Release - Release if: github.repository_owner == 'npm' && needs.release.outputs.releases runs-on: ubuntu-latest @@ -279,79 +214,54 @@ jobs: run: shell: bash steps: - - name: Create Release PR Comment + - name: Create Release PR Comment Text + id: comment-text uses: actions/github-script@v6 env: RELEASES: ${{ needs.release.outputs.releases }} with: + result-encoding: string script: | const releases = JSON.parse(process.env.RELEASES) const { runId, repo: { owner, repo } } = context const issue_number = releases[0].prNumber - - let body = '## Release Workflow\n\n' - for (const { pkgName, version, url } of releases) { - body += `- \`${pkgName}@${version}\` ${url}\n` - } - - const comments = await github.paginate(github.rest.issues.listComments, { owner, repo, issue_number }) - .then(cs => cs.map(c => ({ id: c.id, login: c.user.login, body: c.body }))) - console.log(`Found comments: ${JSON.stringify(comments, null, 2)}`) - const releaseComments = comments.filter(c => c.login === 'github-actions[bot]' && c.body.includes('Release is at')) - - for (const comment of releaseComments) { - console.log(`Release comment: ${JSON.stringify(comment, null, 2)}`) - await github.rest.issues.deleteComment({ owner, repo, comment_id: comment.id }) - } - const runUrl = `https://github.com/${owner}/${repo}/actions/runs/${runId}` - await github.rest.issues.createComment({ - owner, - repo, - issue_number, - body: `${body}- Workflow run: :arrows_counterclockwise: ${runUrl}`, - }) + + return [ + '## Release Workflow\n', + ...releases.map(r => `- \`${r.pkgName}@${r.version}\` ${r.url}`), + `- Workflow run: :arrows_counterclockwise: ${runUrl}`, + ].join('\n') + - name: Create Release PR Comment + id: create-comment + uses: peter-evans/create-or-update-comment@v3 + with: + issue-number: ${{ fromJSON(needs.release.outputs.releases)[0].prNumber }} + body: ${{ steps.comment-text.outputs.result }} release-integration: needs: release name: Release Integration - if: needs.release.outputs.release - runs-on: ubuntu-latest - defaults: - run: - shell: bash + if: needs.release.outputs.releases + uses: ./.github/workflows/release-integration.yml permissions: - deployments: write id-token: write - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - ref: ${{ fromJSON(needs.release.outputs.release).tagName }} - - name: Setup Node - uses: actions/setup-node@v3 - with: - node-version: 18.x - - name: Install npm@latest - run: | - npm i --prefer-online --no-fund --no-audit -g npm@latest - npm config set '//registry.npmjs.org/:_authToken'=\${PUBLISH_TOKEN} - - name: Publish - env: - PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} - run: npm publish --provenance + secrets: + PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} + with: + releases: ${{ needs.release.outputs.releases }} post-release-integration: - needs: [ release, release-integration ] + needs: [ release, release-integration, post-release ] name: Post Release Integration - Release - if: github.repository_owner == 'npm' && needs.release.outputs.release && always() + if: github.repository_owner == 'npm' && needs.release.outputs.releases && always() runs-on: ubuntu-latest defaults: run: shell: bash steps: - - name: Get Needs Result - id: needs-result + - name: Get Post Release Conclusion + id: conclusion run: | if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then result="x" @@ -361,39 +271,38 @@ jobs: result="white_check_mark" fi echo "result=$result" >> $GITHUB_OUTPUT - - name: Update Release PR Comment + - name: Find Release PR Comment + uses: peter-evans/find-comment@v2 + id: found-comment + with: + issue-number: ${{ fromJSON(needs.release.outputs.releases)[0].prNumber }} + comment-author: 'github-actions[bot]' + body-includes: '## Release Workflow' + - name: Create Release PR Comment Text + id: comment-text + if: steps.found-comment.outputs.comment-id uses: actions/github-script@v6 env: - PR_NUMBER: ${{ fromJSON(needs.release.outputs.release).prNumber }} - RESULT: ${{ steps.needs-result.outputs.result }} + RESULT: ${{ steps.conclusion.outputs.result }} + BODY: ${{ steps.found-comment.outputs.comment-body }} with: + result-encoding: string script: | - const { PR_NUMBER: issue_number, RESULT } = process.env - const { runId, repo: { owner, repo } } = context - - const comments = await github.paginate(github.rest.issues.listComments, { owner, repo, issue_number }) - const updateComment = comments.find(c => - c.user.login === 'github-actions[bot]' && - c.body.startsWith('## Release Workflow\n\n') && - c.body.includes(runId) - ) - - if (updateComment) { - console.log('Found comment to update:', JSON.stringify(updateComment, null, 2)) - let body = updateComment.body.replace(/Workflow run: :[a-z_]+:/, `Workflow run: :${RESULT}:`) - const tagCodeowner = RESULT !== 'white_check_mark' - if (tagCodeowner) { - body += `\n\n:rotating_light:` - body += ` @npm/cli-team: The post-release workflow failed for this release.` - body += ` Manual steps may need to be taken after examining the workflow output` - body += ` from the above workflow run. :rotating_light:` - } - await github.rest.issues.updateComment({ - owner, - repo, - body, - comment_id: updateComment.id, - }) - } else { - console.log('No matching comments found:', JSON.stringify(comments, null, 2)) + const { RESULT, BODY } = process.env + const body = [BODY.replace(/(Workflow run: :)[a-z_]+(:)/, `$1${RESULT}$2`)] + if (RESULT !== 'white_check_mark') { + body.push(':rotating_light::rotating_light::rotating_light:') + body.push([ + '@npm/cli-team: The post-release workflow failed for this release.', + 'Manual steps may need to be taken after examining the workflow output.' + ].join(' ')) + body.push(':rotating_light::rotating_light::rotating_light:') } + return body.join('\n\n').trim() + - name: Update Release PR Comment + if: steps.comment-text.outputs.result + uses: peter-evans/create-or-update-comment@v3 + with: + comment-id: ${{ steps.found-comment.outputs.comment-id }} + body: ${{ steps.comment-text.outputs.result }} + edit-mode: 'replace' diff --git a/.gitignore b/.gitignore index 00bdaf2b..1bcc5e25 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ # ignore everything in the root /* +# transient test directories +tap-testdir*/ # keep these !**/.gitignore @@ -34,3 +36,4 @@ !/SECURITY.md !/tap-snapshots/ !/test/ +!/tsconfig.json diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 92661b3b..4c4a46ef 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "7.5.4" + ".": "7.6.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 232b63ed..451daa10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## [7.6.0](https://github.com/npm/node-semver/compare/v7.5.4...v7.6.0) (2024-01-31) + +### Features + +* [`a7ab13a`](https://github.com/npm/node-semver/commit/a7ab13a46201e342d34e84a989632b380f755baf) [#671](https://github.com/npm/node-semver/pull/671) preserve pre-release and build parts of a version on coerce (#671) (@madtisa, madtisa, @wraithgar) + +### Chores + +* [`816c7b2`](https://github.com/npm/node-semver/commit/816c7b2cbfcb1986958a290f941eddfd0441139e) [#667](https://github.com/npm/node-semver/pull/667) postinstall for dependabot template-oss PR (@lukekarrys) +* [`0bd24d9`](https://github.com/npm/node-semver/commit/0bd24d943cbd1a7f6a2b8d384590bfa98559e1de) [#667](https://github.com/npm/node-semver/pull/667) bump @npmcli/template-oss from 4.21.1 to 4.21.3 (@dependabot[bot]) +* [`e521932`](https://github.com/npm/node-semver/commit/e521932f115a81030f4e7c34e8631cdd3c6a108b) [#652](https://github.com/npm/node-semver/pull/652) postinstall for dependabot template-oss PR (@lukekarrys) +* [`8873991`](https://github.com/npm/node-semver/commit/88739918080debeb239aae840b35c07436148e50) [#652](https://github.com/npm/node-semver/pull/652) chore: chore: postinstall for dependabot template-oss PR (@lukekarrys) +* [`f317dc8`](https://github.com/npm/node-semver/commit/f317dc8689781bcfd98e2c32b46157276acdd47c) [#652](https://github.com/npm/node-semver/pull/652) bump @npmcli/template-oss from 4.19.0 to 4.21.0 (@dependabot[bot]) +* [`7303db1`](https://github.com/npm/node-semver/commit/7303db1fe54d6905b23ccb0162878e37d73535ef) [#658](https://github.com/npm/node-semver/pull/658) add clean() test for build metadata (#658) (@jethrodaniel) +* [`6240d75`](https://github.com/npm/node-semver/commit/6240d75a7c620b0a222f05969a91fdc3dc2be0fb) [#656](https://github.com/npm/node-semver/pull/656) add missing quotes in README.md (#656) (@zyxkad) +* [`14d263f`](https://github.com/npm/node-semver/commit/14d263faa156e408a033b9b12a2f87735c2df42c) [#625](https://github.com/npm/node-semver/pull/625) postinstall for dependabot template-oss PR (@lukekarrys) +* [`7c34e1a`](https://github.com/npm/node-semver/commit/7c34e1ac1bcc0bc6579b30745c96075c69bd0332) [#625](https://github.com/npm/node-semver/pull/625) bump @npmcli/template-oss from 4.18.1 to 4.19.0 (@dependabot[bot]) +* [`123e0b0`](https://github.com/npm/node-semver/commit/123e0b03287e1af295ef82d55f55c16805596f35) [#622](https://github.com/npm/node-semver/pull/622) postinstall for dependabot template-oss PR (@lukekarrys) +* [`737d5e1`](https://github.com/npm/node-semver/commit/737d5e1cf10e631bab8a28594aa2d5c9d4090814) [#622](https://github.com/npm/node-semver/pull/622) bump @npmcli/template-oss from 4.18.0 to 4.18.1 (@dependabot[bot]) +* [`cce6180`](https://github.com/npm/node-semver/commit/cce61804ba6f997225a1267135c06676fe0524d2) [#598](https://github.com/npm/node-semver/pull/598) postinstall for dependabot template-oss PR (@lukekarrys) +* [`b914a3d`](https://github.com/npm/node-semver/commit/b914a3d0d26ca27d2685053d7d390af4e02eedd9) [#598](https://github.com/npm/node-semver/pull/598) bump @npmcli/template-oss from 4.17.0 to 4.18.0 (@dependabot[bot]) + ## [7.5.4](https://github.com/npm/node-semver/compare/v7.5.3...v7.5.4) (2023-07-07) ### Bug Fixes diff --git a/README.md b/README.md index 53ea9b52..a9d3a278 100644 --- a/README.md +++ b/README.md @@ -529,6 +529,10 @@ tuple. For example, `1.2.3.4` will return `2.3.4` in rtl mode, not `4.0.0`. `1.2.3/4` will return `4.0.0`, because the `4` is not a part of any other overlapping SemVer tuple. +If the `options.includePrerelease` flag is set, then the `coerce` result will contain +prerelease and build parts of a version. For example, `1.2.3.4-rc.1+rev.2` +will preserve prerelease `rc.1` and build `rev.2` in the result. + ### Clean * `clean(version)`: Clean a string to be a valid semver if possible @@ -543,7 +547,7 @@ ex. * `s.clean(' = v 2.1.5-foo')`: `null` * `s.clean(' = v 2.1.5-foo', { loose: true })`: `'2.1.5-foo'` * `s.clean('=v2.1.5')`: `'2.1.5'` -* `s.clean(' =v2.1.5')`: `2.1.5` +* `s.clean(' =v2.1.5')`: `'2.1.5'` * `s.clean(' 2.1.5 ')`: `'2.1.5'` * `s.clean('~1.0.0')`: `null` diff --git a/functions/coerce.js b/functions/coerce.js index febbff9c..b378dcea 100644 --- a/functions/coerce.js +++ b/functions/coerce.js @@ -19,34 +19,42 @@ const coerce = (version, options) => { let match = null if (!options.rtl) { - match = version.match(re[t.COERCE]) + match = version.match(options.includePrerelease ? re[t.COERCEFULL] : re[t.COERCE]) } else { // Find the right-most coercible string that does not share // a terminus with a more left-ward coercible string. // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4' + // With includePrerelease option set, '1.2.3.4-rc' wants to coerce '2.3.4-rc', not '2.3.4' // // Walk through the string checking with a /g regexp // Manually set the index so as to pick up overlapping matches. // Stop when we get a match that ends at the string end, since no // coercible string can be more right-ward without the same terminus. + const coerceRtlRegex = options.includePrerelease ? re[t.COERCERTLFULL] : re[t.COERCERTL] let next - while ((next = re[t.COERCERTL].exec(version)) && + while ((next = coerceRtlRegex.exec(version)) && (!match || match.index + match[0].length !== version.length) ) { if (!match || next.index + next[0].length !== match.index + match[0].length) { match = next } - re[t.COERCERTL].lastIndex = next.index + next[1].length + next[2].length + coerceRtlRegex.lastIndex = next.index + next[1].length + next[2].length } // leave it in a clean state - re[t.COERCERTL].lastIndex = -1 + coerceRtlRegex.lastIndex = -1 } if (match === null) { return null } - return parse(`${match[2]}.${match[3] || '0'}.${match[4] || '0'}`, options) + const major = match[2] + const minor = match[3] || '0' + const patch = match[4] || '0' + const prerelease = options.includePrerelease && match[5] ? `-${match[5]}` : '' + const build = options.includePrerelease && match[6] ? `+${match[6]}` : '' + + return parse(`${major}.${minor}.${patch}${prerelease}${build}`, options) } module.exports = coerce diff --git a/internal/re.js b/internal/re.js index 21150b3e..fd8920e7 100644 --- a/internal/re.js +++ b/internal/re.js @@ -154,12 +154,17 @@ createToken('XRANGELOOSE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAINLOOSE]}$`) // Coercion. // Extract anything that could conceivably be a part of a valid semver -createToken('COERCE', `${'(^|[^\\d])' + +createToken('COERCEPLAIN', `${'(^|[^\\d])' + '(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` + `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + - `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + + `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`) +createToken('COERCE', `${src[t.COERCEPLAIN]}(?:$|[^\\d])`) +createToken('COERCEFULL', src[t.COERCEPLAIN] + + `(?:${src[t.PRERELEASE]})?` + + `(?:${src[t.BUILD]})?` + `(?:$|[^\\d])`) createToken('COERCERTL', src[t.COERCE], true) +createToken('COERCERTLFULL', src[t.COERCEFULL], true) // Tilde ranges. // Meaning is "reasonably at or greater than" diff --git a/package.json b/package.json index c145eca2..f00c6bdd 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "semver", - "version": "7.5.4", + "version": "7.6.0", "description": "The semantic version parser used by npm.", "main": "index.js", "scripts": { "test": "tap", "snap": "tap", - "lint": "eslint \"**/*.js\"", + "lint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"", "postlint": "template-oss-check", "lintfix": "npm run lint -- --fix", "posttest": "npm run lint", @@ -14,7 +14,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.17.0", + "@npmcli/template-oss": "4.21.3", "tap": "^16.0.0" }, "license": "ISC", @@ -53,17 +53,8 @@ "author": "GitHub Inc.", "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.17.0", + "version": "4.21.3", "engines": ">=10", - "ciVersions": [ - "10.0.0", - "10.x", - "12.x", - "14.x", - "16.x", - "18.x" - ], - "npmSpec": "8", "distPaths": [ "classes/", "functions/", diff --git a/release-please-config.json b/release-please-config.json index 73d1e353..559ef7d8 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -1,36 +1,42 @@ { - "exclude-packages-from-root": true, "group-pull-request-title-pattern": "chore: release ${version}", "pull-request-title-pattern": "chore: release${component} ${version}", "changelog-sections": [ { "type": "feat", "section": "Features", - "hidden": false + "hidden": false, + "collapse": false }, { "type": "fix", "section": "Bug Fixes", - "hidden": false + "hidden": false, + "collapse": false }, { "type": "docs", "section": "Documentation", - "hidden": false + "hidden": false, + "collapse": false }, { "type": "deps", "section": "Dependencies", - "hidden": false + "hidden": false, + "collapse": false }, { "type": "chore", - "hidden": true + "section": "Chores", + "hidden": false, + "collapse": false } ], "packages": { ".": { "package-name": "" } - } + }, + "prerelease-type": "pre" } diff --git a/test/functions/clean.js b/test/functions/clean.js index 1df155bf..830e824b 100644 --- a/test/functions/clean.js +++ b/test/functions/clean.js @@ -17,6 +17,7 @@ test('clean tests', (t) => { ['~1.2.3', null], ['<=1.2.3', null], ['1.2.x', null], + ['0.12.0-dev.1150+3c22cecee', '0.12.0-dev.1150'], ].forEach(([range, version]) => { const msg = `clean(${range}) = ${version}` t.equal(clean(range), version, msg) diff --git a/test/functions/coerce.js b/test/functions/coerce.js index ad9f199f..24e2ff76 100644 --- a/test/functions/coerce.js +++ b/test/functions/coerce.js @@ -110,13 +110,47 @@ test('coerce tests', (t) => { ['1.2.3/6', '6.0.0', { rtl: true }], ['1.2.3.4', '2.3.4', { rtl: true }], ['1.2.3.4xyz', '2.3.4', { rtl: true }], + + ['1-rc.5', '1.0.0-rc.5', { includePrerelease: true }], + ['1.2-rc.5', '1.2.0-rc.5', { includePrerelease: true }], + ['1.2.3-rc.5', '1.2.3-rc.5', { includePrerelease: true }], + ['1.2.3-rc.5/a', '1.2.3-rc.5', { includePrerelease: true }], + ['1.2.3.4-rc.5', '1.2.3', { includePrerelease: true }], + ['1.2.3.4+rev.6', '1.2.3', { includePrerelease: true }], + + ['1+rev.6', '1.0.0+rev.6', { includePrerelease: true }], + ['1.2+rev.6', '1.2.0+rev.6', { includePrerelease: true }], + ['1.2.3+rev.6', '1.2.3+rev.6', { includePrerelease: true }], + ['1.2.3+rev.6/a', '1.2.3+rev.6', { includePrerelease: true }], + ['1.2.3.4-rc.5', '1.2.3', { includePrerelease: true }], + ['1.2.3.4+rev.6', '1.2.3', { includePrerelease: true }], + + ['1-rc.5+rev.6', '1.0.0-rc.5+rev.6', { includePrerelease: true }], + ['1.2-rc.5+rev.6', '1.2.0-rc.5+rev.6', { includePrerelease: true }], + ['1.2.3-rc.5+rev.6', '1.2.3-rc.5+rev.6', { includePrerelease: true }], + ['1.2.3-rc.5+rev.6/a', '1.2.3-rc.5+rev.6', { includePrerelease: true }], + + ['1.2-rc.5+rev.6', '1.2.0-rc.5+rev.6', { rtl: true, includePrerelease: true }], + ['1.2.3-rc.5+rev.6', '1.2.3-rc.5+rev.6', { rtl: true, includePrerelease: true }], + ['1.2.3.4-rc.5+rev.6', '2.3.4-rc.5+rev.6', { rtl: true, includePrerelease: true }], + ['1.2.3.4-rc.5', '2.3.4-rc.5', { rtl: true, includePrerelease: true }], + ['1.2.3.4+rev.6', '2.3.4+rev.6', { rtl: true, includePrerelease: true }], + ['1.2.3.4-rc.5+rev.6/7', '7.0.0', { rtl: true, includePrerelease: true }], + ['1.2.3.4-rc/7.5+rev.6', '7.5.0+rev.6', { rtl: true, includePrerelease: true }], + ['1.2.3.4/7-rc.5+rev.6', '7.0.0-rc.5+rev.6', { rtl: true, includePrerelease: true }], ] coerceToValid.forEach(([input, expected, options]) => { - const msg = `coerce(${input}) should become ${expected}` - t.same((coerce(input, options) || {}).version, expected, msg) + const coerceExpression = `coerce(${input}, ${JSON.stringify(options)})` + const coercedVersion = coerce(input, options) || {} + const expectedVersion = parse(expected) + t.equal(expectedVersion.compare(coercedVersion), 0, + `${coerceExpression} should be equal to ${expectedVersion}`) + t.equal(expectedVersion.compareBuild(coercedVersion), 0, + `${coerceExpression} build should be equal to ${expectedVersion}`) }) t.same(valid(coerce('42.6.7.9.3-alpha')), '42.6.7') + t.same(valid(coerce('42.6.7-alpha+rev.1', { includePrerelease: true })), '42.6.7-alpha') t.same(valid(coerce('v2')), '2.0.0') t.end()