diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 96d8eaf..8da2a45 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,7 +4,7 @@ version: 2 updates: - package-ecosystem: npm - directory: "/" + directory: / schedule: interval: daily allow: diff --git a/.github/matchers/tap.json b/.github/matchers/tap.json index ef11419..2c81ea9 100644 --- a/.github/matchers/tap.json +++ b/.github/matchers/tap.json @@ -29,4 +29,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index d46429e..60bb334 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -10,18 +10,28 @@ on: jobs: audit: + name: Audit Dependencies + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: - node-version: 16.x - - name: Update npm to latest + node-version: 18.x + - name: Install npm@latest run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund --package-lock - - run: npm audit + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund --package-lock + - name: Run Audit + run: npm audit diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml new file mode 100644 index 0000000..6dad88c --- /dev/null +++ b/.github/workflows/ci-release.yml @@ -0,0 +1,210 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: CI - Release + +on: + workflow_call: + inputs: + ref: + required: true + type: string + check-sha: + required: true + type: string + +jobs: + lint-all: + name: Lint All + if: github.repository_owner == 'npm' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Get Workflow Job + uses: actions/github-script@v6 + + 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.3.1 + id: check + + 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: + ref: ${{ inputs.ref }} + - 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 + with: + node-version: 18.x + - name: Install npm@latest + run: npm i --prefer-online --no-fund --no-audit -g npm@latest + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund + - name: Lint + run: npm run lint --ignore-scripts + - name: Post Lint + run: npm run postlint --ignore-scripts + - name: Conclude Check + uses: LouisBrunner/checks-action@v1.3.1 + if: always() + with: + token: ${{ secrets.GITHUB_TOKEN }} + conclusion: ${{ job.status }} + check_id: ${{ steps.check.outputs.check_id }} + + test-all: + name: Test All - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd + node-version: + - 14.17.0 + - 14.x + - 16.13.0 + - 16.x + - 18.0.0 + - 18.x + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Get Workflow Job + uses: actions/github-script@v6 + + 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.3.1 + id: check + + 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: + ref: ${{ inputs.ref }} + - 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 + 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@latest + if: ${{ !startsWith(matrix.node-version, '10.') }} + run: npm i --prefer-online --no-fund --no-audit -g npm@latest + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" + - name: Test + run: npm test --ignore-scripts + - name: Conclude Check + uses: LouisBrunner/checks-action@v1.3.1 + if: always() + with: + token: ${{ secrets.GITHUB_TOKEN }} + conclusion: ${{ job.status }} + check_id: ${{ steps.check.outputs.check_id }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3671e3b..a6c934a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,8 +5,6 @@ name: CI on: workflow_dispatch: pull_request: - branches: - - '*' push: branches: - main @@ -16,55 +14,124 @@ on: - cron: "0 9 * * 1" jobs: + engines: + name: Engines - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + node-version: + - 14.17.0 + - 16.13.0 + - 18.0.0 + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - 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 + 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@latest + if: ${{ !startsWith(matrix.node-version, '10.') }} + run: npm i --prefer-online --no-fund --no-audit -g npm@latest + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund --engines-strict + lint: + name: Lint + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: - node-version: 16.x - - name: Update npm to latest + node-version: 18.x + - name: Install npm@latest run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - run: npm run lint + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund + - name: Lint + run: npm run lint --ignore-scripts + - name: Post Lint + run: npm run postlint --ignore-scripts test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' strategy: fail-fast: false matrix: - node-version: - - 12.13.0 - - 12.x - - 14.15.0 - - 14.x - - 16.0.0 - - 16.x platform: - - os: ubuntu-latest + - name: Linux + os: ubuntu-latest shell: bash - - os: macos-latest + - name: macOS + os: macos-latest shell: bash - - os: windows-latest + - name: Windows + os: windows-latest shell: cmd + node-version: + - 14.17.0 + - 14.x + - 16.13.0 + - 16.x + - 18.0.0 + - 18.x runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - name: Update to workable npm (windows) + - 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: | @@ -74,15 +141,17 @@ jobs: node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz cd .. rmdir /s /q package - - name: Update npm to 7 - # If we do test on npm 10 it needs npm7 + - name: Install npm@7 if: startsWith(matrix.node-version, '10.') run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Update npm to latest + - name: Install npm@latest if: ${{ !startsWith(matrix.node-version, '10.') }} run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - name: add tap problem matcher + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund + - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" - - run: npm i --ignore-scripts --no-audit --no-fund - - run: npm test --ignore-scripts + - name: Test + run: npm test --ignore-scripts diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index cfd0db3..66b9498 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,6 +1,6 @@ # This file is automatically added by @npmcli/template-oss. Do not edit. -name: "CodeQL" +name: CodeQL on: push: @@ -8,7 +8,6 @@ on: - main - latest pull_request: - # The branches below must be a subset of the branches above branches: - main - latest @@ -24,21 +23,16 @@ jobs: actions: read contents: read security-events: write - - strategy: - fail-fast: false - matrix: - language: [ javascript ] - steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: - languages: ${{ matrix.language }} + languages: javascript - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/post-dependabot.yml b/.github/workflows/post-dependabot.yml index b6e81e6..4393859 100644 --- a/.github/workflows/post-dependabot.yml +++ b/.github/workflows/post-dependabot.yml @@ -1,43 +1,121 @@ # This file is automatically added by @npmcli/template-oss. Do not edit. -name: Post Dependabot Actions +name: Post Dependabot on: pull_request -# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions permissions: contents: write jobs: - template-oss-apply: + template-oss: + name: template-oss + if: github.repository_owner == 'npm' && github.actor == 'dependabot[bot]' runs-on: ubuntu-latest - if: github.actor == 'dependabot[bot]' + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.ref }} + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: - node-version: 16.x - - name: Update npm to latest + node-version: 18.x + - name: Install npm@latest run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - name: Dependabot metadata + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund + - name: Fetch Dependabot Metadata id: metadata - uses: dependabot/fetch-metadata@v1.1.1 + uses: dependabot/fetch-metadata@v1 with: - github-token: "${{ secrets.GITHUB_TOKEN }}" - - name: npm install and commit + github-token: ${{ secrets.GITHUB_TOKEN }} + + # Dependabot can update multiple directories so we output which directory + # it is acting on so we can run the command for the correct root or workspace + - name: Get Dependabot Directory if: contains(steps.metadata.outputs.dependency-names, '@npmcli/template-oss') + id: flags + run: | + dependabot_dir="${{ steps.metadata.outputs.directory }}" + if [[ "$dependabot_dir" == "/" ]]; then + echo "::set-output name=workspace::-iwr" + else + # strip leading slash from directory so it works as a + # a path to the workspace flag + echo "::set-output name=workspace::-w ${dependabot_dir#/}" + fi + + - name: Apply Changes + if: steps.flags.outputs.workspace + id: apply + run: | + npm run template-oss-apply ${{ steps.flags.outputs.workspace }} + if [[ `git status --porcelain` ]]; then + echo "::set-output name=changes::true" + fi + # This only sets the conventional commit prefix. This workflow can't reliably determine + # what the breaking change is though. If a BREAKING CHANGE message is required then + # this PR check will fail and the commit will be amended with stafftools + if [[ "${{ steps.metadata.outputs.update-type }}" == "version-update:semver-major" ]]; then + prefix='feat!' + else + prefix='chore!' + fi + echo "::set-output name=message::$prefix: postinstall for dependabot template-oss PR" + + # This step will fail if template-oss has made any workflow updates. It is impossible + # for a workflow to update other workflows. In the case it does fail, we continue + # and then try to apply only a portion of the changes in the next step + - name: Push All Changes + if: steps.apply.outputs.changes + id: push + continue-on-error: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - gh pr checkout ${{ github.event.pull_request.number }} - npm install --ignore-scripts --no-audit --no-fund - npm run template-oss-apply - git add . - git commit -am "chore: postinstall for dependabot template-oss PR" + git commit -am "${{ steps.apply.outputs.message }}" git push - npm run lint + + # If the previous step failed, then reset the commit and remove any workflow changes + # and attempt to commit and push again. This is helpful because we will have a commit + # with the correct prefix that we can then --amend with @npmcli/stafftools later. + - name: Push All Changes Except Workflows + if: steps.apply.outputs.changes && steps.push.outcome == 'failure' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git reset HEAD~ + git checkout HEAD -- .github/workflows/ + git clean -fd .github/workflows/ + git commit -am "${{ steps.apply.outputs.message }}" + git push + + # Check if all the necessary template-oss changes were applied. Since we continued + # on errors in one of the previous steps, this check will fail if our follow up + # only applied a portion of the changes and we need to followup manually. + # + # Note that this used to run `lint` and `postlint` but that will fail this action + # if we've also shipped any linting changes separate from template-oss. We do + # linting in another action, so we want to fail this one only if there are + # template-oss changes that could not be applied. + - name: Check Changes + if: steps.apply.outputs.changes + run: | + npm exec --offline ${{ steps.flags.outputs.workspace }} -- template-oss-check + + - name: Fail on Breaking Change + if: steps.apply.outputs.changes && startsWith(steps.apply.outputs.message, 'feat!') + run: | + echo "This PR has a breaking change. Run 'npx -p @npmcli/stafftools gh template-oss-fix'" + echo "for more information on how to fix this with a BREAKING CHANGE footer." + exit 1 diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 7223076..1a1d1ee 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -1,6 +1,6 @@ # This file is automatically added by @npmcli/template-oss. Do not edit. -name: Pull Request Linting +name: Pull Request on: pull_request: @@ -11,28 +11,38 @@ on: - synchronize jobs: - check: - name: Check PR Title or Commits + commitlint: + name: Lint Commits + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 + - name: Checkout + uses: actions/checkout@v3 with: fetch-depth: 0 - - name: Setup git user + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: - node-version: 16.x - - name: Update npm to latest + node-version: 18.x + - name: Install npm@latest run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - name: Install deps - run: npm i -D @commitlint/cli @commitlint/config-conventional - - name: Check commits OR PR title - env: - PR_TITLE: ${{ github.event.pull_request.title }} + - name: npm Version + run: npm -v + - 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/main --to ${{ github.event.pull_request.head.sha }} \ - || echo $PR_TITLE | npx --offline commitlint -V + 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' + run: | + echo ${{ github.event.pull_request.title }} | npx --offline commitlint -V diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml deleted file mode 100644 index ab3a910..0000000 --- a/.github/workflows/release-please.yml +++ /dev/null @@ -1,26 +0,0 @@ -# This file is automatically added by @npmcli/template-oss. Do not edit. - -name: Release Please - -on: - push: - branches: - - main - - latest - -jobs: - release-please: - runs-on: ubuntu-latest - steps: - - uses: google-github-actions/release-please-action@v3 - id: release - with: - release-type: node - changelog-types: > - [ - {"type":"feat","section":"Features","hidden":false}, - {"type":"fix","section":"Bug Fixes","hidden":false}, - {"type":"docs","section":"Documentation","hidden":false}, - {"type":"deps","section":"Dependencies","hidden":false}, - {"type":"chore","hidden":true} - ] diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..2f7dee0 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,298 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: Release + +on: + workflow_dispatch: + push: + branches: + - main + - latest + +permissions: + contents: write + pull-requests: write + checks: write + +jobs: + release: + outputs: + pr: ${{ steps.release.outputs.pr }} + releases: ${{ steps.release.outputs.releases }} + release-flags: ${{ steps.release.outputs.release-flags }} + 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 }} + name: Release + if: github.repository_owner == 'npm' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Checkout + uses: actions/checkout@v3 + - 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 + with: + node-version: 18.x + - name: Install npm@latest + run: npm i --prefer-online --no-fund --no-audit -g npm@latest + - name: npm Version + run: npm -v + - 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 }} ${{ github.event_name }} + - name: Post Pull Request Comment + 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 }} + with: + script: | + const { REF_NAME, PR_NUMBER } = process.env + const repo = { owner: context.repo.owner, repo: context.repo.repo } + const issue = { ...repo, issue_number: PR_NUMBER } + + const { data: workflow } = await github.rest.actions.getWorkflowRun({ ...repo, run_id: context.runId }) + + let body = '## Release Manager\n\n' + + const comments = await github.paginate(github.rest.issues.listComments, issue) + 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 Rerun for This Release\n\n` + body += `This PR will be updated and CI will run for every non-\`chore:\` commit that is pushed to \`main\`. ` + body += `To force CI to rerun, run this command:\n\n` + body += `\`\`\`\ngh workflow run release.yml -r ${REF_NAME}\n\`\`\`` + + if (commentId) { + await github.rest.issues.updateComment({ ...repo, comment_id: commentId, body }) + } else { + const { data: comment } = await github.rest.issues.createComment({ ...issue, body }) + commentId = comment?.id + } + + return commentId + - name: Get Workflow Job + uses: actions/github-script@v6 + if: steps.release.outputs.pr-number + id: check-output + env: + JOB_NAME: "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.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 } + - name: Create Check + uses: LouisBrunner/checks-action@v1.3.1 + id: check + if: steps.release.outputs.pr-number + with: + 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 }} + name: Update - Release + if: github.repository_owner == 'npm' && needs.release.outputs.pr + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + ref: ${{ needs.release.outputs.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 + with: + node-version: 18.x + - name: Install npm@latest + run: npm i --prefer-online --no-fund --no-audit -g npm@latest + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund + - 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 + npm run rp-pull-request --ignore-scripts --if-present + - name: Commit + id: commit + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git commit --all --amend --no-edit || true + git push --force-with-lease + echo "::set-output name=sha::$(git rev-parse HEAD)" + - name: Get Workflow Job + uses: actions/github-script@v6 + + 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.3.1 + id: check + + with: + 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.3.1 + if: always() + with: + token: ${{ secrets.GITHUB_TOKEN }} + conclusion: ${{ job.status }} + check_id: ${{ needs.release.outputs.check-id }} + + ci: + name: CI - Release + needs: [ release, update ] + if: needs.release.outputs.pr + uses: ./.github/workflows/ci-release.yml + with: + ref: ${{ needs.release.outputs.branch }} + check-sha: ${{ needs.update.outputs.sha }} + + post-ci: + needs: [ release, update, ci ] + name: Post CI - Release + if: github.repository_owner == 'npm' && needs.release.outputs.pr && always() + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Get Needs Result + id: needs-result + run: | + result="" + if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then + result="failure" + elif [[ "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then + result="cancelled" + else + result="success" + fi + echo "::set-output name=result::$result" + - name: Conclude Check + uses: LouisBrunner/checks-action@v1.3.1 + if: always() + with: + token: ${{ secrets.GITHUB_TOKEN }} + conclusion: ${{ steps.needs-result.outputs.result }} + check_id: ${{ needs.update.outputs.check-id }} + + post-release: + needs: release + name: Post Release - Release + if: github.repository_owner == 'npm' && needs.release.outputs.releases + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Checkout + uses: actions/checkout@v3 + - 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 + with: + node-version: 18.x + - name: Install npm@latest + run: npm i --prefer-online --no-fund --no-audit -g npm@latest + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund + - name: Run Post Release Actions + env: + RELEASES: ${{ needs.release.outputs.releases }} + run: | + npm run rp-release --ignore-scripts --if-present ${{ join(fromJSON(needs.release.outputs.release-flags), ' ') }} diff --git a/.gitignore b/.gitignore index be5771f..0ec3c84 100644 --- a/.gitignore +++ b/.gitignore @@ -4,23 +4,25 @@ /* # keep these -!/.eslintrc.local.* !**/.gitignore -!/docs/ -!/tap-snapshots/ -!/test/ -!/map.js -!/scripts/ -!/README* -!/LICENSE* -!/CHANGELOG* !/.commitlintrc.js !/.eslintrc.js +!/.eslintrc.local.* !/.github/ !/.gitignore !/.npmrc -!/CODE_OF_CONDUCT.md -!/SECURITY.md +!/.release-please-manifest.json !/bin/ +!/CHANGELOG* +!/CODE_OF_CONDUCT.md +!/docs/ !/lib/ +!/LICENSE* +!/map.js !/package.json +!/README* +!/release-please-config.json +!/scripts/ +!/SECURITY.md +!/tap-snapshots/ +!/test/ diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..8390882 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "10.0.0" +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 99fb591..445dd4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## [10.0.0](https://github.com/npm/npm-package-arg/compare/v9.1.0...v10.0.0) (2022-10-18) + +### ⚠️ BREAKING CHANGES + +* `x` and `x@` now return the same spec as `x@*` +* `npm-package-arg` is now compatible with the following semver range for node: `^14.17.0 || ^16.13.0 || >=18.0.0` + +### Features + +* [`749ccad`](https://github.com/npm/npm-package-arg/commit/749ccad1516e0e61db989669326165bfdb6b7227) [#104](https://github.com/npm/npm-package-arg/pull/104) postinstall for dependabot template-oss PR (@lukekarrys) + +### Bug Fixes + +* [`d2b87c0`](https://github.com/npm/npm-package-arg/commit/d2b87c083f6f83d01d869281631a0d544190edcf) [#97](https://github.com/npm/npm-package-arg/pull/97) standardize `x` `x@` and `x@*` (#97) (@wraithgar) +* [`7b9cb25`](https://github.com/npm/npm-package-arg/commit/7b9cb25e2b2788ae7b0c9a9b33ca8701a030b8aa) [#108](https://github.com/npm/npm-package-arg/pull/108) resolve relative urls that start with file:// (@lukekarrys) + +### Dependencies + +* [`b3f0b93`](https://github.com/npm/npm-package-arg/commit/b3f0b93abae31e8e3a186c5f6ebedd3616b0764a) [#117](https://github.com/npm/npm-package-arg/pull/117) bump proc-log from 2.0.1 to 3.0.0 (#117) +* [`7162848`](https://github.com/npm/npm-package-arg/commit/71628486d9f96ef522e28cb32e15ff8d26cf3903) [#116](https://github.com/npm/npm-package-arg/pull/116) bump validate-npm-package-name from 4.0.0 to 5.0.0 (#116) +* [`3110d8f`](https://github.com/npm/npm-package-arg/commit/3110d8f954a76e237649bd478d0cb2fbc95f6afc) [#115](https://github.com/npm/npm-package-arg/pull/115) `hosted-git-info@6.0.0` (#115) + ## [9.1.0](https://github.com/npm/npm-package-arg/compare/v9.0.2...v9.1.0) (2022-06-22) diff --git a/lib/npa.js b/lib/npa.js index 61fee07..10af67b 100644 --- a/lib/npa.js +++ b/lib/npa.js @@ -39,11 +39,12 @@ function npa (arg, where) { spec = arg } else if (nameEndsAt > 0) { name = namePart - spec = arg.slice(nameEndsAt + 1) + spec = arg.slice(nameEndsAt + 1) || '*' } else { const valid = validatePackageName(arg) if (valid.validForOldPackages) { name = arg + spec = '*' } else { spec = arg } @@ -113,7 +114,7 @@ function Result (opts) { this.name = undefined this.escapedName = undefined this.scope = undefined - this.rawSpec = opts.rawSpec == null ? '' : opts.rawSpec + this.rawSpec = opts.rawSpec || '' this.saveSpec = opts.saveSpec this.fetchSpec = opts.fetchSpec if (opts.name) { @@ -241,8 +242,10 @@ function fromFile (res, where) { rawNoPrefix = rawSpec.replace(/^file:/, '') } // turn file:/../foo into file:../foo - if (/^\/\.\.?(\/|$)/.test(rawNoPrefix)) { - const rawSpec = res.rawSpec.replace(/^file:\//, 'file:') + // for 1, 2 or 3 leading slashes since we attempted + // in the previous step to make it a file protocol url with a leading slash + if (/^\/{1,3}\.\.?(\/|$)/.test(rawNoPrefix)) { + const rawSpec = res.rawSpec.replace(/^file:\/{1,3}/, 'file:') resolvedUrl = new url.URL(rawSpec, `file://${path.resolve(where)}/`) specUrl = new url.URL(rawSpec) rawNoPrefix = rawSpec.replace(/^file:/, '') @@ -381,7 +384,7 @@ function fromAlias (res, where) { function fromRegistry (res) { res.registry = true - const spec = res.rawSpec === '' ? 'latest' : res.rawSpec.trim() + const spec = res.rawSpec.trim() // no save spec for registry components as we save based on the fetched // version, not on the argument so this can't compute that. res.saveSpec = null diff --git a/package.json b/package.json index c6cf62e..9ade534 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "npm-package-arg", - "version": "9.1.0", + "version": "10.0.0", "description": "Parse the things that can be arguments to `npm install`", "main": "./lib/npa.js", "directories": { @@ -11,20 +11,17 @@ "lib/" ], "dependencies": { - "hosted-git-info": "^5.0.0", - "proc-log": "^2.0.1", + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", "semver": "^7.3.5", - "validate-npm-package-name": "^4.0.0" + "validate-npm-package-name": "^5.0.0" }, "devDependencies": { - "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "4.3.2", + "@npmcli/eslint-config": "^4.0.0", + "@npmcli/template-oss": "4.6.1", "tap": "^16.0.1" }, "scripts": { - "preversion": "npm test", - "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags", "test": "tap", "snap": "tap", "npmclilint": "npmcli-lint", @@ -46,13 +43,17 @@ }, "homepage": "https://github.com/npm/npm-package-arg", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" }, "tap": { - "branches": 97 + "branches": 97, + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.6.0" + "version": "4.6.1" } } diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..73d1e35 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,36 @@ +{ + "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 + }, + { + "type": "fix", + "section": "Bug Fixes", + "hidden": false + }, + { + "type": "docs", + "section": "Documentation", + "hidden": false + }, + { + "type": "deps", + "section": "Dependencies", + "hidden": false + }, + { + "type": "chore", + "hidden": true + } + ], + "packages": { + ".": { + "package-name": "" + } + } +} diff --git a/test/basic.js b/test/basic.js index 404c2e8..13b4cce 100644 --- a/test/basic.js +++ b/test/basic.js @@ -44,10 +44,10 @@ t.test('basic', function (t) { name: '@foo/bar', escapedName: '@foo%2fbar', scope: '@foo', - rawSpec: '', + rawSpec: '*', saveSpec: null, - fetchSpec: 'latest', - type: 'tag', + fetchSpec: '*', + type: 'range', }, '@foo/bar@': { @@ -55,10 +55,10 @@ t.test('basic', function (t) { name: '@foo/bar', escapedName: '@foo%2fbar', scope: '@foo', - rawSpec: '', + rawSpec: '*', saveSpec: null, - fetchSpec: 'latest', - type: 'tag', + fetchSpec: '*', + type: 'range', }, '@foo/bar@baz': { @@ -113,11 +113,11 @@ t.test('basic', function (t) { registry: true, name: 'bar', escapedName: 'bar', - type: 'tag', + type: 'range', raw: 'bar', - rawSpec: '', + rawSpec: '*', saveSpec: null, - fetchSpec: 'latest', + fetchSpec: '*', }, }, @@ -366,10 +366,10 @@ t.test('basic', function (t) { name: 'git', type: 'alias', subSpec: { - type: 'tag', + type: 'range', registry: true, name: 'not-git', - fetchSpec: 'latest', + fetchSpec: '*', }, raw: 'git@npm:not-git', }, @@ -461,6 +461,33 @@ t.test('basic', function (t) { raw: 'file:/.path/to/foo', }, + 'file:./path/to/foo': { + name: null, + escapedName: null, + type: 'directory', + saveSpec: 'file:path/to/foo', + fetchSpec: '/test/a/b/path/to/foo', + raw: 'file:./path/to/foo', + }, + + 'file:/./path/to/foo': { + name: null, + escapedName: null, + type: 'directory', + saveSpec: 'file:path/to/foo', + fetchSpec: '/test/a/b/path/to/foo', + raw: 'file:/./path/to/foo', + }, + + 'file://./path/to/foo': { + name: null, + escapedName: null, + type: 'directory', + saveSpec: 'file:path/to/foo', + fetchSpec: '/test/a/b/path/to/foo', + raw: 'file://./path/to/foo', + }, + 'file:../path/to/foo': { name: null, escapedName: null, @@ -479,6 +506,15 @@ t.test('basic', function (t) { raw: 'file:/../path/to/foo', }, + 'file://../path/to/foo': { + name: null, + escapedName: null, + type: 'directory', + saveSpec: 'file:../path/to/foo', + fetchSpec: '/test/a/path/to/foo', + raw: 'file://../path/to/foo', + }, + 'file:///path/to/foo': { name: null, escapedName: null, @@ -517,6 +553,7 @@ t.test('basic', function (t) { escapedName: null, type: 'directory', saveSpec: 'file:', + fetchSpec: '/test/a/b', raw: 'file://.', }, @@ -550,9 +587,9 @@ t.test('basic', function (t) { foo: { name: 'foo', escapedName: 'foo', - type: 'tag', + type: 'range', saveSpec: null, - fetchSpec: 'latest', + fetchSpec: '*', raw: 'foo', }, diff --git a/test/realize-package-specifier.js b/test/realize-package-specifier.js index 63c9483..03d6651 100644 --- a/test/realize-package-specifier.js +++ b/test/realize-package-specifier.js @@ -8,7 +8,7 @@ test('realize-package-specifier', function (t) { result = npa('a.tar.gz', '/test/a/b') t.equal(result.type, 'file', 'local tarball') result = npa('d', '/test/a/b') - t.equal(result.type, 'tag', 'remote package') + t.equal(result.type, 'range', 'remote package') result = npa('file:./a.tar.gz', '/test/a/b') t.equal(result.type, 'file', 'local tarball') result = npa('file:./b', '/test/a/b')