nvm-sh/nvm

16 workflows · maturity 50% · 10 patterns · GitHub ↗

Security 52.5/100

Practices

✓ Matrix✓ Permissions✓ Security scan○ AI review○ Cache○ Concurrency○ Reusable workflows

Detected patterns

Security dimensions

permissions
25
security scan
12.5
supply chain
0
secret handling
0
harden runner
15

Tools: github/codeql-action/analyze, github/codeql-action/autobuild, github/codeql-action/init

Workflows (16)

codeql-analysis perms security .github/workflows/codeql-analysis.yml
Triggers
push, pull_request, schedule
Runs on
ubuntu-latest
Jobs
CodeQL-Build
Actions
github/codeql-action/init, github/codeql-action/autobuild, github/codeql-action/analyze
View raw YAML
name: "Code scanning - action"

on:
  push:
  pull_request:
  schedule:
    - cron: '0 17 * * 4'

permissions:
  contents: read

jobs:
  CodeQL-Build:

    # CodeQL runs on ubuntu-latest and windows-latest
    permissions:
      actions: read  # for github/codeql-action/init to get workflow details
      contents: read  # for actions/checkout to fetch code
      security-events: write  # for github/codeql-action/autobuild to send a status report
    runs-on: ubuntu-latest

    steps:
    - name: Checkout repository
      uses: actions/checkout@v6
      with:
        persist-credentials: false

    # Initializes the CodeQL tools for scanning.
    - name: Initialize CodeQL
      uses: github/codeql-action/init@v4
      # Override language selection by uncommenting this and choosing your languages
      # with:
      #   languages: go, javascript, csharp, python, cpp, java

    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
    # If this step fails, then you should remove it and run the build manually (see below)
    - name: Autobuild
      uses: github/codeql-action/autobuild@v4

    # ℹ️ Command-line programs to run using the OS shell.
    # 📚 https://git.io/JvXDl

    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
    #    and modify them (or add more) to build your code if your project
    #    uses a compiled language

    #- run: |
    #   make bootstrap
    #   make release

    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@v4
latest-npm matrix perms .github/workflows/latest-npm.yml
Triggers
pull_request, push
Runs on
ubuntu-latest, ubuntu-latest, ubuntu-latest
Jobs
matrix, nodes, node
Matrix
include, include.node-version, node-version→ ${{ fromJson(needs.matrix.outputs.latest) }}, 0.10, 0.12, 14.16, 14.17, 20.4, 20.5, 21, 4.4, 4.5, 4.6, 5.9, 6.1, 9.0, 9.1, 9.2
Actions
step-security/harden-runner, ljharb/actions/node/matrix, step-security/harden-runner, ljharb/actions/node/install
Commands
  • npm --version
  • . ./nvm.sh ; nvm install-latest-npm
  • npm --version
View raw YAML
name: 'Tests: `nvm install-latest-npm`'

on: [pull_request, push]

permissions:
  contents: read

jobs:
  matrix:
    runs-on: ubuntu-latest
    outputs:
      latest: ${{ steps.set-matrix.outputs.requireds }}
    steps:
      - name: Harden Runner
        uses: step-security/harden-runner@v2
        with:
          allowed-endpoints:
            iojs.org:443
            nodejs.org:443
            raw.githubusercontent.com:443
      - uses: ljharb/actions/node/matrix@main
        id: set-matrix
        with:
          versionsAsRoot: true
          type: majors
          preset: '>=1'

  nodes:
    needs: [matrix]
    permissions:
      contents: read
    name: 'nvm install-latest-npm'
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        node-version: ${{ fromJson(needs.matrix.outputs.latest) }}
        include:
          - node-version: "21"
          - node-version: "20.5"
          - node-version: "20.4"
          - node-version: "14.17"
          - node-version: "14.16"
          - node-version: "9.2"
          - node-version: "9.1"
          - node-version: "9.0"
          - node-version: "6.1"
          - node-version: "5.9"
          - node-version: "4.6"
          - node-version: "4.5"
          - node-version: "4.4"
          - node-version: "0.12"
          - node-version: "0.10"

    steps:
      - name: Harden Runner
        uses: step-security/harden-runner@v2
        with:
          allowed-endpoints:
            github.com:443
            raw.githubusercontent.com:443
            iojs.org:443
            nodejs.org:443
            registry.npmjs.org:443
      - uses: actions/checkout@v6
      - uses: ljharb/actions/node/install@main
        name: 'install node'
        with:
          node-version: ${{ matrix.node-version }}
          skip-ls-check: true
          skip-install: true
          skip-latest-npm: true
      - run: npm --version
      - run: '. ./nvm.sh ; nvm install-latest-npm'
        name: 'nvm install-latest-npm'
      - run: npm --version

  node:
    permissions:
      contents: none
    name: 'nvm install-latest-npm'
    needs: [nodes]
    runs-on: ubuntu-latest
    steps:
      - run: true
lint perms .github/workflows/lint.yml
Triggers
pull_request, push
Runs on
ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest
Jobs
eclint, dockerfile_lint, doctoc, test_naming, all
Actions
step-security/harden-runner, ljharb/actions/node/install, step-security/harden-runner, ljharb/actions/node/install, step-security/harden-runner, ljharb/actions/node/install, step-security/harden-runner
Commands
  • npm run eclint
  • npm run dockerfile_lint
  • npm run doctoc:check
  • ./rename_test.sh --check
View raw YAML
name: 'Tests: linting'

on: [pull_request, push]

permissions:
  contents: read

jobs:
  eclint:
    runs-on: ubuntu-latest
    steps:
      - uses: step-security/harden-runner@v2
        with:
          allowed-endpoints:
            github.com:443
            raw.githubusercontent.com:443
            nodejs.org:443
            registry.npmjs.org:443
      - uses: actions/checkout@v6
      - uses: ljharb/actions/node/install@main
        name: 'nvm install ${{ matrix.node-version }} && npm install'
        with:
          node-version: 'lts/*'
      - run: npm run eclint

  dockerfile_lint:
    runs-on: ubuntu-latest
    steps:
      - uses: step-security/harden-runner@v2
        with:
          allowed-endpoints:
            ghcr.io:443
            github.com:443
            raw.githubusercontent.com:443
            pkg-containers.githubusercontent.com:443
            nodejs.org:443
            registry.npmjs.org:443
      - uses: actions/checkout@v6
      - uses: ljharb/actions/node/install@main
        name: 'nvm install ${{ matrix.node-version }} && npm install'
        with:
          node-version: 'lts/*'
      - run: npm run dockerfile_lint

  doctoc:
    runs-on: ubuntu-latest
    steps:
      - uses: step-security/harden-runner@v2
        with:
          allowed-endpoints:
            github.com:443
            raw.githubusercontent.com:443
            nodejs.org:443
            registry.npmjs.org:443
      - uses: actions/checkout@v6
      - uses: ljharb/actions/node/install@main
        name: 'nvm install ${{ matrix.node-version }} && npm install'
        with:
          node-version: 'lts/*'
      - run: npm run doctoc:check

  test_naming:
    runs-on: ubuntu-latest
    steps:
      - uses: step-security/harden-runner@v2
        with:
          allowed-endpoints:
            github.com:443
            raw.githubusercontent.com:443
      - uses: actions/checkout@v6
      - name: check tests filenames
        run: ./rename_test.sh --check

  all:
    permissions:
      contents: none
    name: 'all linting'
    needs: [eclint, dockerfile_lint, doctoc, test_naming]
    runs-on: ubuntu-latest
    steps:
      - run: true
nodejs-org perms .github/workflows/nodejs-org.yml
Triggers
push, workflow_dispatch
Runs on
ubuntu-latest
Jobs
update-nodejs-org
Actions
step-security/harden-runner
Commands
  • set -euo pipefail INPUT_VERSION="${{ inputs.version }}" if [ -n "${INPUT_VERSION}" ]; then TAG="${INPUT_VERSION}" elif [ "${GITHUB_REF_TYPE}" = "tag" ]; then TAG="${GITHUB_REF#refs/tags/}" else TAG="$(gh api "repos/${GITHUB_REPOSITORY}/releases/latest" --jq '.tag_name')" fi if ! printf '%s\n' "${TAG}" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then echo "::notice::Tag '${TAG}' does not match expected format vX.Y.Z, skipping" exit 0 fi printf 'tag=%s\n' "${TAG}" >> "${GITHUB_OUTPUT}"
  • set -euo pipefail BRANCH="nvm-${{ steps.version.outputs.tag }}" gh repo fork nodejs/nodejs.org --clone=false 2>&1 || true FORK_OWNER="$(gh api user --jq '.login')" DEFAULT_BRANCH="$(gh api repos/nodejs/nodejs.org --jq '.default_branch')" UPSTREAM_SHA="$(gh api "repos/nodejs/nodejs.org/git/ref/heads/${DEFAULT_BRANCH}" --jq '.object.sha')" # Create or reset branch on fork to upstream HEAD if ! gh api "repos/${FORK_OWNER}/nodejs.org/git/refs" \ -f "ref=refs/heads/${BRANCH}" \ -f "sha=${UPSTREAM_SHA}" > /dev/null 2>&1; then gh api "repos/${FORK_OWNER}/nodejs.org/git/refs/heads/${BRANCH}" \ -X PATCH \ -f "sha=${UPSTREAM_SHA}" \ -f "force=true" > /dev/null fi printf 'fork_owner=%s\n' "${FORK_OWNER}" >> "${GITHUB_OUTPUT}" printf 'branch=%s\n' "${BRANCH}" >> "${GITHUB_OUTPUT}"
  • set -euo pipefail NEW_VERSION="${{ steps.version.outputs.tag }}" FORK_OWNER="${{ steps.fork.outputs.fork_owner }}" BRANCH="${{ steps.fork.outputs.branch }}" FILE_PATH="apps/site/snippets/en/download/nvm.bash" PATTERN='nvm-sh/nvm/v[0-9]+\.[0-9]+\.[0-9]+/install\.sh' REPLACEMENT="nvm-sh/nvm/${NEW_VERSION}/install.sh" # Get file content via API FILE_RESPONSE="$(gh api "repos/${FORK_OWNER}/nodejs.org/contents/${FILE_PATH}?ref=${BRANCH}")" FILE_SHA="$(printf '%s' "${FILE_RESPONSE}" | jq -r '.sha')" printf '%s' "${FILE_RESPONSE}" | jq -r '.content' | base64 -d > "${RUNNER_TEMP}/nvm.bash" # Validate exactly 1 match MATCH_COUNT="$(grep -cE "${PATTERN}" "${RUNNER_TEMP}/nvm.bash" || true)" if [ "${MATCH_COUNT}" -eq 0 ]; then echo "::error::No nvm version pattern found in ${FILE_PATH}" exit 1 fi if [ "${MATCH_COUNT}" -ne 1 ]; then echo "::error::Expected exactly 1 nvm version match in ${FILE_PATH}, found ${MATCH_COUNT}" exit 1 fi # Replace and check for changes cp "${RUNNER_TEMP}/nvm.bash" "${RUNNER_TEMP}/nvm.bash.orig" sed -i -E "s|${PATTERN}|${REPLACEMENT}|g" "${RUNNER_TEMP}/nvm.bash" if cmp -s "${RUNNER_TEMP}/nvm.bash" "${RUNNER_TEMP}/nvm.bash.orig"; then echo "::notice::English snippet already has version ${NEW_VERSION}" exit 0 fi if ! grep -qF "${REPLACEMENT}" "${RUNNER_TEMP}/nvm.bash"; then echo "::error::Replacement verification failed in ${FILE_PATH}" exit 1 fi # Update file via GitHub API (avoids git push workflow scope requirement) NEW_CONTENT_B64="$(base64 -w 0 < "${RUNNER_TEMP}/nvm.bash")" gh api "repos/${FORK_OWNER}/nodejs.org/contents/${FILE_PATH}" \ -X PUT \ -f "message=meta: bump nvm to ${NEW_VERSION}" \ -f "content=${NEW_CONTENT_B64}" \ -f "sha=${FILE_SHA}" \ -f "branch=${BRANCH}" \ -f "committer[name]=github-actions[bot]" \ -f "committer[email]=41898282+github-actions[bot]@users.noreply.github.com" > /dev/null printf 'updated=true\n' >> "${GITHUB_OUTPUT}"
  • set -euo pipefail NEW_VERSION="${{ steps.version.outputs.tag }}" FORK_OWNER="${{ steps.fork.outputs.fork_owner }}" BRANCH="${{ steps.fork.outputs.branch }}" BODY="Updates the English nvm install snippet to [\`${NEW_VERSION}\`](https://github.com/nvm-sh/nvm/releases/tag/${NEW_VERSION}). The translation system handles other locales. Ref: https://github.com/nodejs/nodejs.org/issues/8628" gh pr create \ --repo nodejs/nodejs.org \ --head "${FORK_OWNER}:${BRANCH}" \ --title "meta: bump nvm to ${NEW_VERSION}" \ --body "${BODY}"
View raw YAML
name: 'Update nodejs.org'

on:
  push:
    tags:
      - 'v*'
  workflow_dispatch:
    inputs:
      version:
        description: 'nvm version tag (e.g., v0.40.4). Defaults to latest release.'
        required: false
        default: ''

permissions:
  contents: read

jobs:
  update-nodejs-org:
    if: github.repository == 'nvm-sh/nvm' && github.actor == 'ljharb'
    permissions:
      contents: none
    name: 'Create PR to nodejs/nodejs.org'
    runs-on: ubuntu-latest
    steps:
      - name: Harden Runner
        uses: step-security/harden-runner@v2
        with:
          allowed-endpoints:
            github.com:443
            api.github.com:443

      - name: Extract and validate version
        id: version
        run: |
          set -euo pipefail

          INPUT_VERSION="${{ inputs.version }}"

          if [ -n "${INPUT_VERSION}" ]; then
            TAG="${INPUT_VERSION}"
          elif [ "${GITHUB_REF_TYPE}" = "tag" ]; then
            TAG="${GITHUB_REF#refs/tags/}"
          else
            TAG="$(gh api "repos/${GITHUB_REPOSITORY}/releases/latest" --jq '.tag_name')"
          fi

          if ! printf '%s\n' "${TAG}" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
            echo "::notice::Tag '${TAG}' does not match expected format vX.Y.Z, skipping"
            exit 0
          fi

          printf 'tag=%s\n' "${TAG}" >> "${GITHUB_OUTPUT}"
        env:
          GH_TOKEN: ${{ github.token }}

      - name: Set up fork and branch
        if: steps.version.outputs.tag
        id: fork
        run: |
          set -euo pipefail

          BRANCH="nvm-${{ steps.version.outputs.tag }}"

          gh repo fork nodejs/nodejs.org --clone=false 2>&1 || true
          FORK_OWNER="$(gh api user --jq '.login')"

          DEFAULT_BRANCH="$(gh api repos/nodejs/nodejs.org --jq '.default_branch')"
          UPSTREAM_SHA="$(gh api "repos/nodejs/nodejs.org/git/ref/heads/${DEFAULT_BRANCH}" --jq '.object.sha')"

          # Create or reset branch on fork to upstream HEAD
          if ! gh api "repos/${FORK_OWNER}/nodejs.org/git/refs" \
            -f "ref=refs/heads/${BRANCH}" \
            -f "sha=${UPSTREAM_SHA}" > /dev/null 2>&1; then
            gh api "repos/${FORK_OWNER}/nodejs.org/git/refs/heads/${BRANCH}" \
              -X PATCH \
              -f "sha=${UPSTREAM_SHA}" \
              -f "force=true" > /dev/null
          fi

          printf 'fork_owner=%s\n' "${FORK_OWNER}" >> "${GITHUB_OUTPUT}"
          printf 'branch=%s\n' "${BRANCH}" >> "${GITHUB_OUTPUT}"
        env:
          GH_TOKEN: ${{ secrets.NODEJS_ORG_TOKEN }}

      - name: Update nvm version in English snippet
        if: steps.version.outputs.tag
        id: update
        run: |
          set -euo pipefail

          NEW_VERSION="${{ steps.version.outputs.tag }}"
          FORK_OWNER="${{ steps.fork.outputs.fork_owner }}"
          BRANCH="${{ steps.fork.outputs.branch }}"
          FILE_PATH="apps/site/snippets/en/download/nvm.bash"
          PATTERN='nvm-sh/nvm/v[0-9]+\.[0-9]+\.[0-9]+/install\.sh'
          REPLACEMENT="nvm-sh/nvm/${NEW_VERSION}/install.sh"

          # Get file content via API
          FILE_RESPONSE="$(gh api "repos/${FORK_OWNER}/nodejs.org/contents/${FILE_PATH}?ref=${BRANCH}")"
          FILE_SHA="$(printf '%s' "${FILE_RESPONSE}" | jq -r '.sha')"
          printf '%s' "${FILE_RESPONSE}" | jq -r '.content' | base64 -d > "${RUNNER_TEMP}/nvm.bash"

          # Validate exactly 1 match
          MATCH_COUNT="$(grep -cE "${PATTERN}" "${RUNNER_TEMP}/nvm.bash" || true)"

          if [ "${MATCH_COUNT}" -eq 0 ]; then
            echo "::error::No nvm version pattern found in ${FILE_PATH}"
            exit 1
          fi

          if [ "${MATCH_COUNT}" -ne 1 ]; then
            echo "::error::Expected exactly 1 nvm version match in ${FILE_PATH}, found ${MATCH_COUNT}"
            exit 1
          fi

          # Replace and check for changes
          cp "${RUNNER_TEMP}/nvm.bash" "${RUNNER_TEMP}/nvm.bash.orig"
          sed -i -E "s|${PATTERN}|${REPLACEMENT}|g" "${RUNNER_TEMP}/nvm.bash"

          if cmp -s "${RUNNER_TEMP}/nvm.bash" "${RUNNER_TEMP}/nvm.bash.orig"; then
            echo "::notice::English snippet already has version ${NEW_VERSION}"
            exit 0
          fi

          if ! grep -qF "${REPLACEMENT}" "${RUNNER_TEMP}/nvm.bash"; then
            echo "::error::Replacement verification failed in ${FILE_PATH}"
            exit 1
          fi

          # Update file via GitHub API (avoids git push workflow scope requirement)
          NEW_CONTENT_B64="$(base64 -w 0 < "${RUNNER_TEMP}/nvm.bash")"
          gh api "repos/${FORK_OWNER}/nodejs.org/contents/${FILE_PATH}" \
            -X PUT \
            -f "message=meta: bump nvm to ${NEW_VERSION}" \
            -f "content=${NEW_CONTENT_B64}" \
            -f "sha=${FILE_SHA}" \
            -f "branch=${BRANCH}" \
            -f "committer[name]=github-actions[bot]" \
            -f "committer[email]=41898282+github-actions[bot]@users.noreply.github.com" > /dev/null

          printf 'updated=true\n' >> "${GITHUB_OUTPUT}"
        env:
          GH_TOKEN: ${{ secrets.NODEJS_ORG_TOKEN }}

      - name: Create pull request
        if: steps.update.outputs.updated
        run: |
          set -euo pipefail

          NEW_VERSION="${{ steps.version.outputs.tag }}"
          FORK_OWNER="${{ steps.fork.outputs.fork_owner }}"
          BRANCH="${{ steps.fork.outputs.branch }}"

          BODY="Updates the English nvm install snippet to [\`${NEW_VERSION}\`](https://github.com/nvm-sh/nvm/releases/tag/${NEW_VERSION}). The translation system handles other locales.

          Ref: https://github.com/nodejs/nodejs.org/issues/8628"

          gh pr create \
            --repo nodejs/nodejs.org \
            --head "${FORK_OWNER}:${BRANCH}" \
            --title "meta: bump nvm to ${NEW_VERSION}" \
            --body "${BODY}"
        env:
          GH_TOKEN: ${{ secrets.NODEJS_ORG_TOKEN }}
nvm-install-test matrix perms .github/workflows/nvm-install-test.yml
Triggers
pull_request, push, workflow_dispatch
Runs on
ubuntu-latest, ubuntu-latest, ubuntu-latest
Jobs
matrix, test, finisher
Matrix
has-nvmrc, ref, shell-level→ ${{ fromJson(needs.matrix.outputs.matrix) }}, 1 shlvl, 2 shlvls, no nvmrc, nvmrc
Commands
  • if [ "${{ github.event_name }}" == "workflow_dispatch" ] && [ -n "${{ github.event.inputs.ref }}" ]; then echo "matrix=\"[\"${{ github.event.inputs.ref }}\"]\"" >> $GITHUB_OUTPUT else TAGS="$((echo "HEAD" && git tag --sort=-v:refname --merged HEAD --format='%(refname:strip=2) %(creatordate:short)' | grep '^v' | while read tag date; do if [ "$(uname)" == "Darwin" ]; then timestamp=$(date -j -f "%Y-%m-%d" "$date" +%s) threshold=$(date -j -v-4y +%s) else timestamp=$(date -d "$date" +%s) threshold=$(date -d "4 years ago" +%s) fi if [ $timestamp -ge $threshold ]; then echo "$tag"; fi done) | xargs)" echo $TAGS TAGS_JSON=$(printf "%s\n" $TAGS | jq -R . | jq -sc .) echo "matrix=${TAGS_JSON}" >> $GITHUB_OUTPUT fi
  • if [ '${{ matrix.ref }}' = 'HEAD' ]; then REF="$(git rev-parse HEAD)" else REF="${{ matrix.ref }}" fi echo "resolved ref: ${REF}" echo "ref="$REF"" >> $GITHUB_ENV
  • echo $-
  • echo node > .nvmrc
  • curl -I --compressed -v https://nodejs.org/dist/
  • set -e export NVM_INSTALL_VERSION="${ref}" curl -o- "https://raw.githubusercontent.com/nvm-sh/nvm/${ref}/install.sh" | bash
  • set +e . $NVM_DIR/nvm.sh && nvm --version
  • set -ex . $NVM_DIR/nvm.sh echo nvm.sh sourced nvm --version if [ '${{ matrix.has-nvmrc }}' == 'nvmrc' ]; then nvm install fi
View raw YAML
name: 'Tests: nvm install with set -e'

on:
  pull_request:
  push:
  workflow_dispatch:
    inputs:
      ref:
        description: 'git ref to use'
        required: false
        default: 'HEAD'

permissions:
  contents: read

jobs:
  matrix:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.matrix.outputs.matrix }}
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0
      - id: matrix
        run: |
          if [ "${{ github.event_name }}" == "workflow_dispatch" ] && [ -n "${{ github.event.inputs.ref }}" ]; then
            echo "matrix=\"[\"${{ github.event.inputs.ref }}\"]\"" >> $GITHUB_OUTPUT
          else
            TAGS="$((echo "HEAD" && git tag --sort=-v:refname --merged HEAD --format='%(refname:strip=2) %(creatordate:short)' | grep '^v' | while read tag date; do
              if [ "$(uname)" == "Darwin" ]; then
                timestamp=$(date -j -f "%Y-%m-%d" "$date" +%s)
                threshold=$(date -j -v-4y +%s)
              else
                timestamp=$(date -d "$date" +%s)
                threshold=$(date -d "4 years ago" +%s)
              fi
              if [ $timestamp -ge $threshold ]; then echo "$tag"; fi
            done) | xargs)"
            echo $TAGS
            TAGS_JSON=$(printf "%s\n" $TAGS | jq -R . | jq -sc .)
            echo "matrix=${TAGS_JSON}" >> $GITHUB_OUTPUT
          fi

  test:
    needs: [matrix]
    runs-on: ubuntu-latest
    continue-on-error: ${{ matrix.ref == 'v0.40.0' }} # https://github.com/nvm-sh/nvm/issues/3405
    strategy:
      fail-fast: false
      matrix:
        ref: ${{ fromJson(needs.matrix.outputs.matrix) }}
        has-nvmrc:
          - 'no nvmrc'
          - 'nvmrc'
        shell-level:
          - 1 shlvl
          - 2 shlvls

    steps:
      - uses: actions/checkout@v6
      - name: resolve HEAD to sha
        run: |
          if [ '${{ matrix.ref }}' = 'HEAD' ]; then
            REF="$(git rev-parse HEAD)"
          else
            REF="${{ matrix.ref }}"
          fi
          echo "resolved ref: ${REF}"
          echo "ref="$REF"" >> $GITHUB_ENV
      - run: echo $- # which options are set
      - run: echo node > .nvmrc
        if: ${{ matrix.has-nvmrc == 'nvmrc' }}
      - run:  curl -I --compressed -v https://nodejs.org/dist/
      - name: 'install nvm'
        run: |
          set -e
          export NVM_INSTALL_VERSION="${ref}"
          curl -o- "https://raw.githubusercontent.com/nvm-sh/nvm/${ref}/install.sh" | bash
      - name: nvm --version
        run: |
          set +e
          . $NVM_DIR/nvm.sh && nvm --version
      - name: nvm install in 1 shell level, ${{ matrix.has-nvmrc }}
        if: ${{ matrix.shell-level == '1 shlvl' }}
        run: |
          set -ex
          . $NVM_DIR/nvm.sh
          echo nvm.sh sourced
          nvm --version
          if [ '${{ matrix.has-nvmrc }}' == 'nvmrc' ]; then
            nvm install
          fi
      - name: nvm install in 2 shell levels, ${{ matrix.has-nvmrc }}
        if: ${{ matrix.shell-level == '2 shlvls' }}
        run: |
          if [ '${{ matrix.has-nvmrc }}' == 'nvmrc' ]; then
            bash -c "set -ex && . $NVM_DIR/nvm.sh && echo nvm.sh sourced && nvm --version && nvm install"
          else
            bash -c "set -ex && . $NVM_DIR/nvm.sh && echo nvm.sh sourced && nvm --version"
          fi

  finisher:
    runs-on: ubuntu-latest
    needs: [test]
    steps:
      - run: true
rebase perms .github/workflows/rebase.yml
Triggers
pull_request_target
Runs on
ubuntu-latest
Jobs
_
Actions
ljharb/rebase
View raw YAML
name: Automatic Rebase

on: [pull_request_target]

permissions: read-all

jobs:
  _:
    name: "Automatic Rebase"

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v6
      - uses: ljharb/rebase@master
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
release perms .github/workflows/release.yml
Triggers
pull_request, push
Runs on
ubuntu-latest
Jobs
release
Actions
step-security/harden-runner
Commands
  • npm install
  • git config user.name github-actions git config user.email github-actions@github.com git fetch --unshallow --tags -f || git fetch --tags -f
  • echo proceed | make TAG=99.99.99 release
  • git tag | grep v99.99.99
View raw YAML
name: 'Tests: release process'

on: [pull_request, push]

permissions:
  contents: read

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - name: Harden Runner
        uses: step-security/harden-runner@v2
        with:
          allowed-endpoints:
            github.com:443
            api.github.com:443
            objects.githubusercontent.com:443
            raw.githubusercontent.com:443
            release-assets.githubusercontent.com:443
            registry.npmjs.org:443
      - uses: actions/checkout@v6
        with:
          fetch-tags: true
      - uses: actions/setup-node@v6
        with:
          node-version: "14"
      - run: npm install
      - name: Configure git
        run: |
          git config user.name github-actions
          git config user.email github-actions@github.com
          git fetch --unshallow --tags -f || git fetch --tags -f
      - name: Attempt `make release` process
        run: echo proceed | make TAG=99.99.99 release
        env:
          GIT_EDITOR: "sed -i '1 s/^/99.99.99 make release test/'"
      - name: Ensure tag is created
        run: git tag | grep v99.99.99
require-allow-edits perms .github/workflows/require-allow-edits.yml
Triggers
pull_request_target
Runs on
ubuntu-latest
Jobs
_
Actions
ljharb/require-allow-edits
View raw YAML
name: Require “Allow Edits”

on: [pull_request_target]

permissions: read-all

jobs:
  _:
    name: "Require “Allow Edits”"

    runs-on: ubuntu-latest

    steps:
      - uses: ljharb/require-allow-edits@main
shellcheck matrix perms .github/workflows/shellcheck.yml
Triggers
pull_request, push
Runs on
ubuntu-latest, ubuntu-latest
Jobs
shellcheck_matrix, shellcheck
Matrix
file, include, include.file, include.shell, shell→ bash, bash_completion, dash, install.sh, ksh, nvm-exec, nvm.sh, sh
Actions
step-security/harden-runner, Homebrew/actions/setup-homebrew
Commands
  • brew install shellcheck
  • which shellcheck
  • shellcheck --version
  • shellcheck -s ${{ matrix.shell }} ${{ matrix.file }}
View raw YAML
name: 'Tests: shellcheck'

on: [pull_request, push]

permissions:
  contents: read

jobs:
  shellcheck_matrix:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        shell:
          - bash
          - sh
          - dash
          - ksh
        file:
          - nvm.sh
        include:
          - shell: bash
            file: install.sh # only supported on bash
          - shell: bash
            file: bash_completion # only needed in bash/zsh
          - shell: bash
            file: nvm-exec # only runs in bash

    steps:
      - name: Harden Runner
        uses: step-security/harden-runner@v2
        with:
          allowed-endpoints:
            ghcr.io:443
            github.com:443
            pkg-containers.githubusercontent.com:443
            formulae.brew.sh:443
      - uses: actions/checkout@v6
      - name: Set up Homebrew
        uses: Homebrew/actions/setup-homebrew@master
      - name: Install latest shellcheck
        run: brew install shellcheck
        env:
          HOMEBREW_NO_ANALYTICS: 1
      - run: which shellcheck
      - run: shellcheck --version
      - name: Run shellcheck on ${{ matrix.file }}
        run: shellcheck -s ${{ matrix.shell }} ${{ matrix.file }}

  shellcheck:
      permissions:
        contents: none
      needs: [shellcheck_matrix]
      runs-on: ubuntu-latest
      steps:
        - run: true
tests matrix perms .github/workflows/tests.yml
Triggers
push, pull_request
Runs on
ubuntu-latest, ubuntu-latest
Jobs
tests, nvm
Matrix
exclude, exclude.shell, exclude.suite, shell, suite→ bash, dash, install_script, installation_iojs, ksh, sh, slow, sourcing, zsh
Actions
step-security/harden-runner, ljharb/actions/node/install
Commands
  • sudo apt-get update; sudo apt-get install ${{ matrix.shell }}
  • sudo ${{ matrix.shell }} --version 2> /dev/null || dpkg -s ${{ matrix.shell }} 2> /dev/null || which ${{ matrix.shell }}
  • curl --version
  • wget --version
  • npm ls urchin
  • npx which urchin
  • env
  • for attempt in 1 2 3; do timeout 600 make TERM=xterm-256color TEST_SUITE="${{ matrix.suite }}" SHELL="${{ matrix.shell }}" URCHIN="$(npx which urchin)" test-${{ matrix.shell }} && exit 0 EXIT_CODE=$? if [ $EXIT_CODE -ne 124 ]; then exit $EXIT_CODE fi echo "Attempt ${attempt} timed out; retrying..." done echo "All 3 attempts timed out." exit 1
View raw YAML
name: urchin tests

on: [push, pull_request]

permissions:
  contents: read

jobs:
  tests:
    permissions:
      contents: write

    name: "tests"
    runs-on: ubuntu-latest
    timeout-minutes: 30
    defaults:
      run:
        shell: 'script -q -e -c "${{ matrix.shell }} {0}"'

    strategy:
      fail-fast: false
      matrix:
        exclude:
          - shell: sh
            suite: install_script
          - shell: dash
            suite: install_script
          - shell: zsh
            suite: install_script
          - shell: ksh
            suite: install_script
        suite:
          - install_script
          - sourcing
          - slow
          - installation_iojs
        shell:
          - sh
          - bash
          - dash
          - zsh
          # - ksh

    steps:
      - name: Harden Runner
        uses: step-security/harden-runner@v2
        with:
          allowed-endpoints:
            github.com:443
            registry.npmjs.org:443
            raw.githubusercontent.com:443
            nodejs.org:443
            iojs.org:443
            azure.archive.ubuntu.com:80
            packages.microsoft.com:443
      - uses: actions/checkout@v6
      - run: sudo apt-get update; sudo apt-get install ${{ matrix.shell }}
        if: matrix.shell == 'zsh' || matrix.shell == 'ksh'
        # zsh (https://github.com/actions/runner-images/issues/264) and ksh are not in the ubuntu image
        shell: bash
      - run: sudo ${{ matrix.shell }} --version 2> /dev/null || dpkg -s ${{ matrix.shell }} 2> /dev/null || which ${{ matrix.shell }}
      - run: curl --version
      - run: wget --version
      - uses: ljharb/actions/node/install@main
        name: 'npm install && version checks'
        with:
          node-version: 'lts/*'
          skip-ls-check: true
      - run: npm ls urchin
      - run: npx which urchin
      - run: env
      - name: Run tests
        shell: bash
        run: |
          for attempt in 1 2 3; do
            timeout 600 make TERM=xterm-256color TEST_SUITE="${{ matrix.suite }}" SHELL="${{ matrix.shell }}" URCHIN="$(npx which urchin)" test-${{ matrix.shell }} && exit 0
            EXIT_CODE=$?
            if [ $EXIT_CODE -ne 124 ]; then
              exit $EXIT_CODE
            fi
            echo "Attempt ${attempt} timed out; retrying..."
          done
          echo "All 3 attempts timed out."
          exit 1

  nvm:
    permissions:
      contents: none
    name: 'all test suites, all shells'
    needs: [tests]
    runs-on: ubuntu-latest
    steps:
      - run: true
tests-fast matrix perms .github/workflows/tests-fast.yml
Triggers
push, pull_request
Runs on
ubuntu-latest, ubuntu-latest
Jobs
fast, all
Matrix
awk, shell→ bash, dash, gawk, mawk, sh, zsh
Actions
step-security/harden-runner, ljharb/actions/node/install
Commands
  • sudo apt-get update sudo apt-get install -y zsh ${{ matrix.awk }} if [ "${{ matrix.shell }}" != "sh" ] && [ "${{ matrix.shell }}" != "bash" ] && [ "${{ matrix.shell }}" != "zsh" ]; then sudo apt-get install -y ${{ matrix.shell }} fi # Set the selected awk as the default sudo update-alternatives --set awk /usr/bin/${{ matrix.awk }}
  • sudo ${{ matrix.shell }} --version 2> /dev/null || dpkg -s ${{ matrix.shell }} 2> /dev/null || which ${{ matrix.shell }}
  • awk --version 2>&1 | head -1 || awk -W version 2>&1 | head -1
  • curl --version
  • wget --version
  • npm ls urchin
  • npx which urchin
  • env
View raw YAML
name: 'Tests: fast'

on: [push, pull_request]

permissions:
  contents: read

jobs:
  fast:
    permissions:
      contents: read

    name: 'fast (${{ matrix.shell }}, ${{ matrix.awk }})'
    runs-on: ubuntu-latest
    defaults:
      run:
        shell: 'script -q -e -c "${{ matrix.shell }} {0}"'

    strategy:
      fail-fast: false
      matrix:
        shell:
          - sh
          - bash
          - dash
          - zsh
          # - ksh
        awk:
          - gawk
          - mawk

    steps:
      - name: Harden Runner
        uses: step-security/harden-runner@v2
        with:
          allowed-endpoints:
            github.com:443
            registry.npmjs.org:443
            raw.githubusercontent.com:443
            nodejs.org:443
            iojs.org:443
            unofficial-builds.nodejs.org:443
            azure.archive.ubuntu.com:80
            packages.microsoft.com:443
            registry-1.docker.io:443
            auth.docker.io:443
            production.cloudflare.docker.com:443
      - uses: actions/checkout@v6
        with:
          submodules: true
      - name: Install zsh, additional shells, and awk variant
        run: |
          sudo apt-get update
          sudo apt-get install -y zsh ${{ matrix.awk }}
          if [ "${{ matrix.shell }}" != "sh" ] && [ "${{ matrix.shell }}" != "bash" ] && [ "${{ matrix.shell }}" != "zsh" ]; then
            sudo apt-get install -y ${{ matrix.shell }}
          fi
          # Set the selected awk as the default
          sudo update-alternatives --set awk /usr/bin/${{ matrix.awk }}
        shell: bash
      - run: sudo ${{ matrix.shell }} --version 2> /dev/null || dpkg -s ${{ matrix.shell }} 2> /dev/null || which ${{ matrix.shell }}
      - run: awk --version 2>&1 | head -1 || awk -W version 2>&1 | head -1
      - run: curl --version
      - run: wget --version
      - uses: ljharb/actions/node/install@main
        name: 'npm install && version checks'
        with:
          node-version: 'lts/*'
          skip-ls-check: true
      - run: npm ls urchin
      - run: npx which urchin
      - run: env
      - name: Hide system node
        run: |
          if [ -f /usr/local/bin/node ]; then sudo mv /usr/local/bin/node /usr/local/bin/node.bak; fi
          if [ -f /usr/local/bin/npm ]; then sudo mv /usr/local/bin/npm /usr/local/bin/npm.bak; fi
          if [ -f /usr/local/bin/npx ]; then sudo mv /usr/local/bin/npx /usr/local/bin/npx.bak; fi
        shell: bash
      - name: Run fast tests
        run: |
          URCHIN_PATH="$(npx which urchin)"
          unset NVM_CD_FLAGS NVM_BIN NVM_INC
          export NVM_DIR="${{ github.workspace }}"
          export PATH="$(echo "$PATH" | tr ':' '\n' | grep -v '\.nvm' | grep -v 'toolcache' | tr '\n' ':')"
          make TERM=xterm-256color TEST_SUITE="fast" SHELL="${{ matrix.shell }}" URCHIN="$URCHIN_PATH" test-${{ matrix.shell }}
      - name: Restore system node
        if: always()
        run: |
          if [ -f /usr/local/bin/node.bak ]; then sudo mv /usr/local/bin/node.bak /usr/local/bin/node; fi
          if [ -f /usr/local/bin/npm.bak ]; then sudo mv /usr/local/bin/npm.bak /usr/local/bin/npm; fi
          if [ -f /usr/local/bin/npx.bak ]; then sudo mv /usr/local/bin/npx.bak /usr/local/bin/npx; fi
        shell: bash

  all:
    permissions:
      contents: none
    name: 'all fast tests'
    needs: [fast]
    runs-on: ubuntu-latest
    steps:
      - run: true
tests-installation-iojs matrix perms .github/workflows/tests-installation-iojs.yml
Triggers
push, pull_request
Runs on
ubuntu-latest, ubuntu-latest
Jobs
installation_iojs_without_curl, all
Matrix
shell→ bash, dash, sh, zsh
Actions
step-security/harden-runner, ljharb/actions/node/install
Commands
  • sudo apt-get update sudo apt-get install -y zsh if [ "${{ matrix.shell }}" != "sh" ] && [ "${{ matrix.shell }}" != "bash" ] && [ "${{ matrix.shell }}" != "zsh" ]; then sudo apt-get install -y ${{ matrix.shell }} fi
  • sudo ${{ matrix.shell }} --version 2> /dev/null || dpkg -s ${{ matrix.shell }} 2> /dev/null || which ${{ matrix.shell }}
  • wget --version
  • npm ls urchin
  • npx which urchin
  • sudo apt-get remove curl -y
  • ! command -v curl
  • env
View raw YAML
name: 'Tests: installation_iojs'

on: [push, pull_request]

permissions:
  contents: read

jobs:
  installation_iojs_without_curl:
    permissions:
      contents: read

    name: 'installation_iojs without curl (${{ matrix.shell }})'
    runs-on: ubuntu-latest
    defaults:
      run:
        shell: 'script -q -e -c "${{ matrix.shell }} {0}"'

    strategy:
      fail-fast: false
      matrix:
        shell:
          - sh
          - bash
          - dash
          - zsh
          # - ksh

    steps:
      - name: Harden Runner
        uses: step-security/harden-runner@v2
        with:
          allowed-endpoints:
            github.com:443
            registry.npmjs.org:443
            raw.githubusercontent.com:443
            nodejs.org:443
            iojs.org:443
            azure.archive.ubuntu.com:80
            packages.microsoft.com:443
      - uses: actions/checkout@v6
        with:
          submodules: true
      - name: Install zsh and additional shells
        run: |
          sudo apt-get update
          sudo apt-get install -y zsh
          if [ "${{ matrix.shell }}" != "sh" ] && [ "${{ matrix.shell }}" != "bash" ] && [ "${{ matrix.shell }}" != "zsh" ]; then
            sudo apt-get install -y ${{ matrix.shell }}
          fi
        shell: bash
      - run: sudo ${{ matrix.shell }} --version 2> /dev/null || dpkg -s ${{ matrix.shell }} 2> /dev/null || which ${{ matrix.shell }}
      - run: wget --version
      - uses: ljharb/actions/node/install@main
        name: 'npm install && version checks'
        with:
          node-version: 'lts/*'
          skip-ls-check: true
      - run: npm ls urchin
      - run: npx which urchin
      - name: Remove curl
        run: sudo apt-get remove curl -y
        shell: bash
      - run: '! command -v curl'
        shell: bash
      - run: env
      - name: Hide system node
        run: |
          if [ -f /usr/local/bin/node ]; then sudo mv /usr/local/bin/node /usr/local/bin/node.bak; fi
          if [ -f /usr/local/bin/npm ]; then sudo mv /usr/local/bin/npm /usr/local/bin/npm.bak; fi
          if [ -f /usr/local/bin/npx ]; then sudo mv /usr/local/bin/npx /usr/local/bin/npx.bak; fi
        shell: bash
      - name: Run installation_iojs tests
        run: |
          URCHIN_PATH="$(npx which urchin)"
          unset NVM_CD_FLAGS NVM_BIN NVM_INC
          export NVM_DIR="${{ github.workspace }}"
          export PATH="$(echo "$PATH" | tr ':' '\n' | grep -v '\.nvm' | grep -v 'toolcache' | tr '\n' ':')"
          make TERM=xterm-256color TEST_SUITE="installation_iojs" SHELL="${{ matrix.shell }}" URCHIN="$URCHIN_PATH" test-${{ matrix.shell }}
      - name: Restore system node
        if: always()
        run: |
          if [ -f /usr/local/bin/node.bak ]; then sudo mv /usr/local/bin/node.bak /usr/local/bin/node; fi
          if [ -f /usr/local/bin/npm.bak ]; then sudo mv /usr/local/bin/npm.bak /usr/local/bin/npm; fi
          if [ -f /usr/local/bin/npx.bak ]; then sudo mv /usr/local/bin/npx.bak /usr/local/bin/npx; fi
        shell: bash
      - name: Restore curl
        if: always()
        run: sudo apt-get install curl -y
        shell: bash

  all:
    permissions:
      contents: none
    name: 'all installation_iojs tests'
    needs: [installation_iojs_without_curl]
    runs-on: ubuntu-latest
    steps:
      - run: true
tests-installation-node matrix perms .github/workflows/tests-installation-node.yml
Triggers
push, pull_request
Runs on
ubuntu-latest, ubuntu-latest
Jobs
installation_node, all
Matrix
shell, without_curl→ False, True, bash, dash, sh, zsh
Actions
step-security/harden-runner, ljharb/actions/node/install
Commands
  • npm ls urchin
  • npx which urchin
  • docker run --rm \ -v "${{ github.workspace }}:/workspace" \ -w /workspace \ -e "TEST_SHELL=${{ matrix.shell }}" \ -e "TERM=xterm-256color" \ -e "DEBIAN_FRONTEND=noninteractive" \ -e "GITHUB_ACTIONS=true" \ -e "WITHOUT_CURL=${{ matrix.without_curl }}" \ ubuntu:16.04 \ bash -c ' set -ex # Retry apt-get update up to 5 times due to flaky Ubuntu mirrors # apt-get update can return 0 even with partial failures, so check for warnings for i in 1 2 3 4 5; do if apt-get update 2>&1 | tee /tmp/apt-update.log | grep -qE "^(W:|E:|Err:)"; then echo "apt-get update had warnings/errors, attempt $i/5" cat /tmp/apt-update.log sleep $((i * 5)) else break fi done apt-get install -y git curl wget make build-essential python zsh libssl-dev if [ "$TEST_SHELL" != "sh" ] && [ "$TEST_SHELL" != "bash" ]; then apt-get install -y $TEST_SHELL || true fi # Use nvm to install Node.js for running urchin # Node 16 is the last version supporting GLIBC 2.23 (Ubuntu 16.04) export NVM_DIR="/workspace" . /workspace/nvm.sh nvm install 16 nvm use 16 npm ls urchin URCHIN_PATH="$(npx which urchin)" # Remove curl if testing without it if [ "$WITHOUT_CURL" = "true" ]; then apt-get remove curl -y ! command -v curl fi # Now clean up nvm state for the actual tests, but keep NVM_DIR set nvm deactivate || true nvm unalias default || true unset NVM_CD_FLAGS NVM_BIN NVM_INC export PATH="$(echo "$PATH" | tr ":" "\n" | grep -v "\.nvm" | grep -v "toolcache" | tr "\n" ":")" # Clean any cached files from the nvm install above rm -rf "$NVM_DIR/.cache" "$NVM_DIR/versions" "$NVM_DIR/alias" make TEST_SUITE="installation_node" SHELL="$TEST_SHELL" URCHIN="$URCHIN_PATH" test-$TEST_SHELL '
View raw YAML
name: 'Tests: installation_node'

on: [push, pull_request]

permissions:
  contents: read

jobs:
  installation_node:
    permissions:
      contents: read

    name: "installation_node (${{ matrix.shell }}${{ matrix.without_curl && ', without curl' || '' }})"
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        shell:
          - sh
          - bash
          - dash
          - zsh
          # - ksh
        without_curl:
          - false
          - true

    steps:
      - name: Harden Runner
        uses: step-security/harden-runner@v2
        with:
          allowed-endpoints:
            github.com:443
            registry.npmjs.org:443
            raw.githubusercontent.com:443
            nodejs.org:443
            iojs.org:443
            azure.archive.ubuntu.com:80
            packages.microsoft.com:443
            archive.ubuntu.com:80
            security.ubuntu.com:80
            production.cloudflare.docker.com:443
            registry-1.docker.io:443
            auth.docker.io:443
      - uses: actions/checkout@v6
        with:
          submodules: true
      - uses: ljharb/actions/node/install@main
        name: 'npm install && version checks'
        with:
          node-version: 'lts/*'
          skip-ls-check: true
      - run: npm ls urchin
      - run: npx which urchin
      - name: Run installation_node tests in container
        run: |
          docker run --rm \
            -v "${{ github.workspace }}:/workspace" \
            -w /workspace \
            -e "TEST_SHELL=${{ matrix.shell }}" \
            -e "TERM=xterm-256color" \
            -e "DEBIAN_FRONTEND=noninteractive" \
            -e "GITHUB_ACTIONS=true" \
            -e "WITHOUT_CURL=${{ matrix.without_curl }}" \
            ubuntu:16.04 \
            bash -c '
              set -ex

              # Retry apt-get update up to 5 times due to flaky Ubuntu mirrors
              # apt-get update can return 0 even with partial failures, so check for warnings
              for i in 1 2 3 4 5; do
                if apt-get update 2>&1 | tee /tmp/apt-update.log | grep -qE "^(W:|E:|Err:)"; then
                  echo "apt-get update had warnings/errors, attempt $i/5"
                  cat /tmp/apt-update.log
                  sleep $((i * 5))
                else
                  break
                fi
              done

              apt-get install -y git curl wget make build-essential python zsh libssl-dev
              if [ "$TEST_SHELL" != "sh" ] && [ "$TEST_SHELL" != "bash" ]; then
                apt-get install -y $TEST_SHELL || true
              fi

              # Use nvm to install Node.js for running urchin
              # Node 16 is the last version supporting GLIBC 2.23 (Ubuntu 16.04)
              export NVM_DIR="/workspace"
              . /workspace/nvm.sh
              nvm install 16
              nvm use 16

              npm ls urchin
              URCHIN_PATH="$(npx which urchin)"

              # Remove curl if testing without it
              if [ "$WITHOUT_CURL" = "true" ]; then
                apt-get remove curl -y
                ! command -v curl
              fi

              # Now clean up nvm state for the actual tests, but keep NVM_DIR set
              nvm deactivate || true
              nvm unalias default || true
              unset NVM_CD_FLAGS NVM_BIN NVM_INC
              export PATH="$(echo "$PATH" | tr ":" "\n" | grep -v "\.nvm" | grep -v "toolcache" | tr "\n" ":")"

              # Clean any cached files from the nvm install above
              rm -rf "$NVM_DIR/.cache" "$NVM_DIR/versions" "$NVM_DIR/alias"

              make TEST_SUITE="installation_node" SHELL="$TEST_SHELL" URCHIN="$URCHIN_PATH" test-$TEST_SHELL
            '

  all:
    permissions:
      contents: none
    name: 'all installation_node tests'
    needs: [installation_node]
    runs-on: ubuntu-latest
    steps:
      - run: true
tests-xenial matrix perms .github/workflows/tests-xenial.yml
Triggers
push, pull_request
Runs on
ubuntu-latest, ubuntu-latest
Jobs
xenial, all
Matrix
shell→ bash, dash, sh, zsh
Actions
step-security/harden-runner, ljharb/actions/node/install
Commands
  • npm ls urchin
  • npx which urchin
  • docker run --rm \ -v "${{ github.workspace }}:/workspace" \ -w /workspace \ -e "TEST_SHELL=${{ matrix.shell }}" \ -e "TERM=xterm-256color" \ -e "DEBIAN_FRONTEND=noninteractive" \ -e "GITHUB_ACTIONS=true" \ ubuntu:16.04 \ bash -c ' set -ex # Retry apt-get update up to 5 times due to flaky Ubuntu mirrors # apt-get update can return 0 even with partial failures, so check for warnings for i in 1 2 3 4 5; do if apt-get update 2>&1 | tee /tmp/apt-update.log | grep -qE "^(W:|E:|Err:)"; then echo "apt-get update had warnings/errors, attempt $i/5" cat /tmp/apt-update.log sleep $((i * 5)) else break fi done apt-get install -y git curl wget make build-essential python zsh libssl-dev if [ "$TEST_SHELL" != "sh" ] && [ "$TEST_SHELL" != "bash" ]; then apt-get install -y $TEST_SHELL || true fi # Use nvm to install Node.js for running urchin # Node 16 is the last version supporting GLIBC 2.23 (Ubuntu 16.04) export NVM_DIR="/workspace" . /workspace/nvm.sh nvm install 16 nvm use 16 npm ls urchin URCHIN_PATH="$(npx which urchin)" # Now clean up nvm state for the actual tests, but keep NVM_DIR set nvm deactivate || true nvm unalias default || true unset NVM_CD_FLAGS NVM_BIN NVM_INC export PATH="$(echo "$PATH" | tr ":" "\n" | grep -v "\.nvm" | grep -v "toolcache" | tr "\n" ":")" # Clean any cached files from the nvm install above rm -rf "$NVM_DIR/.cache" "$NVM_DIR/versions" "$NVM_DIR/alias" make TEST_SUITE="xenial" SHELL="$TEST_SHELL" URCHIN="$URCHIN_PATH" test-$TEST_SHELL '
View raw YAML
name: 'Tests: xenial'

on: [push, pull_request]

permissions:
  contents: read

jobs:
  xenial:
    permissions:
      contents: read

    name: 'xenial (${{ matrix.shell }})'
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        shell:
          - sh
          - bash
          - dash
          - zsh
          # - ksh

    steps:
      - name: Harden Runner
        uses: step-security/harden-runner@v2
        with:
          allowed-endpoints:
            github.com:443
            registry.npmjs.org:443
            raw.githubusercontent.com:443
            nodejs.org:443
            iojs.org:443
            azure.archive.ubuntu.com:80
            packages.microsoft.com:443
            archive.ubuntu.com:80
            security.ubuntu.com:80
            production.cloudflare.docker.com:443
            registry-1.docker.io:443
            auth.docker.io:443
      - uses: actions/checkout@v6
        with:
          submodules: true
      - uses: ljharb/actions/node/install@main
        name: 'npm install && version checks'
        with:
          node-version: 'lts/*'
          skip-ls-check: true
      - run: npm ls urchin
      - run: npx which urchin
      - name: Run xenial tests in container
        run: |
          docker run --rm \
            -v "${{ github.workspace }}:/workspace" \
            -w /workspace \
            -e "TEST_SHELL=${{ matrix.shell }}" \
            -e "TERM=xterm-256color" \
            -e "DEBIAN_FRONTEND=noninteractive" \
            -e "GITHUB_ACTIONS=true" \
            ubuntu:16.04 \
            bash -c '
              set -ex

              # Retry apt-get update up to 5 times due to flaky Ubuntu mirrors
              # apt-get update can return 0 even with partial failures, so check for warnings
              for i in 1 2 3 4 5; do
                if apt-get update 2>&1 | tee /tmp/apt-update.log | grep -qE "^(W:|E:|Err:)"; then
                  echo "apt-get update had warnings/errors, attempt $i/5"
                  cat /tmp/apt-update.log
                  sleep $((i * 5))
                else
                  break
                fi
              done

              apt-get install -y git curl wget make build-essential python zsh libssl-dev
              if [ "$TEST_SHELL" != "sh" ] && [ "$TEST_SHELL" != "bash" ]; then
                apt-get install -y $TEST_SHELL || true
              fi

              # Use nvm to install Node.js for running urchin
              # Node 16 is the last version supporting GLIBC 2.23 (Ubuntu 16.04)
              export NVM_DIR="/workspace"
              . /workspace/nvm.sh
              nvm install 16
              nvm use 16

              npm ls urchin
              URCHIN_PATH="$(npx which urchin)"

              # Now clean up nvm state for the actual tests, but keep NVM_DIR set
              nvm deactivate || true
              nvm unalias default || true
              unset NVM_CD_FLAGS NVM_BIN NVM_INC
              export PATH="$(echo "$PATH" | tr ":" "\n" | grep -v "\.nvm" | grep -v "toolcache" | tr "\n" ":")"

              # Clean any cached files from the nvm install above
              rm -rf "$NVM_DIR/.cache" "$NVM_DIR/versions" "$NVM_DIR/alias"

              make TEST_SUITE="xenial" SHELL="$TEST_SHELL" URCHIN="$URCHIN_PATH" test-$TEST_SHELL
            '

  all:
    permissions:
      contents: none
    name: 'all xenial tests'
    needs: [xenial]
    runs-on: ubuntu-latest
    steps:
      - run: true
toc perms .github/workflows/toc.yml
Triggers
push
Runs on
ubuntu-latest
Jobs
_
Actions
step-security/harden-runner, ljharb/actions-js-build/commit
Commands
  • git fetch --depth=1 origin +refs/tags/*:refs/tags/*
  • npm install
  • npm run doctoc
View raw YAML
name: update readme TOC

on: [push]

permissions:
  contents: read

jobs:
  _:
    permissions:
      contents: write
    name: "update readme TOC"

    runs-on: ubuntu-latest

    steps:
    - name: Harden Runner
      uses: step-security/harden-runner@v2
      with:
        allowed-endpoints:
          github.com:443
          registry.npmjs.org:443
          api.github.com:443
    - uses: actions/checkout@v6
      with:
        # https://github.com/actions/checkout/issues/217#issue-599945005
        # pulls all commits (needed for lerna / semantic release to correctly version)
        fetch-depth: "0"

    # pulls all tags (needed for lerna / semantic release to correctly version)
    - run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
    - uses: actions/setup-node@v6
      with:
        node-version: 'lts/*'
    - run: npm install
    - run: npm run doctoc
    - name: commit changes
      uses: ljharb/actions-js-build/commit@v3+amendpush
      with:
        amend: true
        force: true
windows-npm matrix perms .github/workflows/windows-npm.yml
Triggers
pull_request, push
Runs on
windows-latest, windows-latest, windows-latest, windows-latest, windows-latest, ubuntu-latest
Jobs
msys_fail_install, msys_matrix, cygwin_matrix, wsl_matrix, wsl_matrix_unofficial, nvm_windows
Matrix
exclude, exclude.npm-node-version, exclude.wsl-distrib, method, npm-node-version, wsl-distrib→ , --default 12, --lts, --no-progress 10, 10, 11, 12, 14, 16, 18, 21, Alpine, Debian, Ubuntu-18.04, Ubuntu-20.04, script
Actions
Vampire/setup-wsl, Vampire/setup-wsl, Vampire/setup-wsl
Commands
  • curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | METHOD=script bash . "$HOME/.nvm/nvm.sh" ! nvm install --lts
  • unset npm_config_prefix if [ "${{ matrix.npm-node-version }}" = "--lts" ]; then curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | bash else curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | METHOD=script bash fi . "$HOME/.nvm/nvm.sh" nvm install ${{ matrix.npm-node-version }}
  • export SITE='https://mirror.clarkson.edu/cygwin/' # see https://archlinux.org/mirrors/clarkson.edu/1603/ for uptime status export SITE='https://mirrors.kernel.org/sourceware/cygwin/' export LOCALDIR="$(pwd)" export ROOTDIR="$USERPROFILE\\cygwin" export PACKAGES='bash,git,curl' curl -fsSLo setup-x86_64.exe 'https://cygwin.com/setup-x86_64.exe' ./setup-x86_64.exe --disable-buggy-antivirus -q -s "$SITE" -l "$LOCALDIR" -R "$ROOTDIR" -P "$PACKAGES" cat >~/setup.sh <<EOM unset npm_config_prefix export NVM_INSTALL_GITHUB_REPO="$NVM_INSTALL_GITHUB_REPO" export NVM_INSTALL_VERSION="$NVM_INSTALL_VERSION" export HOME="$(cygpath -u "$USERPROFILE")" echo "HOME is $HOME" curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | bash ls -l $HOME/.nvm . "$HOME/.nvm/nvm.sh" nvm install --lts nvm deactivate rm -rf "$HOME/.nvm/nvm.sh" curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | METHOD=script bash . "$HOME/.nvm/nvm.sh" nvm install 9 EOM
  • cd %USERPROFILE%\cygwin\bin bash.exe "%USERPROFILE%\setup.sh"
  • sed -i s/ftp.debian.org/archive.debian.org/ /etc/apt/sources.list
  • retry() { local n=0 local max=3 local delay=5 while true; do "$@" && break || { n=$((n+1)) if [ $n -lt $max ]; then echo "Command failed. Attempt $n/$max. Retrying in $delay seconds..." sleep $delay else echo "Command failed after $max attempts." return 1 fi } done } retry apt-get update retry apt-get upgrade --yes retry apt-get install --yes bash git curl ca-certificates wget
  • if [ -z "${{ matrix.method }}" ]; then curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | bash else curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | METHOD="${{matrix.method}}" bash fi . "$HOME/.nvm/nvm.sh" nvm install ${{ matrix.npm-node-version }} node -v
  • if [ -z "${{ matrix.method }}" ]; then curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | bash else curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | METHOD="${{matrix.method}}" bash fi . "$HOME/.nvm/nvm.sh" NVM_NODEJS_ORG_MIRROR=${{ env.NVM_NODEJS_ORG_MIRROR }} nvm install ${{ matrix.npm-node-version }}
View raw YAML
name: 'Tests on Windows: `nvm install`'

on: [pull_request, push]

permissions:
  contents: read

env:
  NVM_INSTALL_GITHUB_REPO: ${{ github.repository }}
  NVM_INSTALL_VERSION: ${{ github.sha }}

jobs:
  msys_fail_install:
    # Default installation does not work due to npm_config_prefix set to C:\npm\prefix
    permissions:
      contents: none
    name: 'MSYS fail prefix nvm install'
    runs-on: windows-latest
    steps:
      - name: Retrieve nvm
        shell: bash
        run: |
          curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | METHOD=script bash
          . "$HOME/.nvm/nvm.sh"
          ! nvm install --lts

  msys_matrix:
    permissions:
      contents: none
    name: 'MSYS nvm install'
    runs-on: windows-latest
    strategy:
      fail-fast: false
      matrix:
        npm-node-version:
          - '--lts'
          - '--default 12'
          - '--no-progress 10'
    steps:
      - name: Retrieve nvm
        shell: bash
        run: |
          unset npm_config_prefix
          if [ "${{ matrix.npm-node-version }}" = "--lts" ]; then
            curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | bash
          else
            curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | METHOD=script bash
          fi
          . "$HOME/.nvm/nvm.sh"
          nvm install ${{ matrix.npm-node-version }}

  cygwin_matrix:
    continue-on-error: true
    permissions:
      contents: none
    name: 'Cygwin nvm install'
    runs-on: windows-latest
    steps:
      - name: Install Cygwin
        shell: bash
        run: |
          export SITE='https://mirror.clarkson.edu/cygwin/' # see https://archlinux.org/mirrors/clarkson.edu/1603/ for uptime status
          export SITE='https://mirrors.kernel.org/sourceware/cygwin/'
          export LOCALDIR="$(pwd)"
          export ROOTDIR="$USERPROFILE\\cygwin"
          export PACKAGES='bash,git,curl'

          curl -fsSLo setup-x86_64.exe 'https://cygwin.com/setup-x86_64.exe'
          ./setup-x86_64.exe --disable-buggy-antivirus -q -s "$SITE" -l "$LOCALDIR" -R "$ROOTDIR" -P "$PACKAGES"

          cat >~/setup.sh <<EOM
            unset npm_config_prefix
            export NVM_INSTALL_GITHUB_REPO="$NVM_INSTALL_GITHUB_REPO"
            export NVM_INSTALL_VERSION="$NVM_INSTALL_VERSION"
            export HOME="$(cygpath -u "$USERPROFILE")"

            echo "HOME is $HOME"
            curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | bash
            ls -l $HOME/.nvm
            . "$HOME/.nvm/nvm.sh"
            nvm install --lts

            nvm deactivate
            rm -rf "$HOME/.nvm/nvm.sh"

            curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | METHOD=script bash
            . "$HOME/.nvm/nvm.sh"
            nvm install 9
          EOM
      - name: Retrieve nvm
        shell: cmd
        run: |
          cd %USERPROFILE%\cygwin\bin
          bash.exe "%USERPROFILE%\setup.sh"

  wsl_matrix:
    continue-on-error: true
    name: 'WSL nvm install'
    defaults:
      run:
          shell: wsl-bash {0}
    runs-on: windows-latest
    env:
      WSLENV: NVM_INSTALL_GITHUB_REPO:NVM_INSTALL_VERSION:/p
    strategy:
      fail-fast: false
      matrix:
        wsl-distrib:
          - Debian
        # - Alpine # fails
          - Ubuntu-20.04
          - Ubuntu-18.04
        npm-node-version:
          - '--lts'
          - '21'
          - '18'
          - '16'
          - '14'
          - '12'
          - '10'
        exclude:
          - wsl-distrib: Ubuntu-18.04
            npm-node-version: '--lts'
          - wsl-distrib: Ubuntu-18.04
            npm-node-version: '21'
          - wsl-distrib: Ubuntu-18.04
            npm-node-version: '18'
          # node v24+ doesn't work on WSL1 (exec format error)
          - wsl-distrib: Debian
            npm-node-version: '--lts'
          - wsl-distrib: Ubuntu-20.04
            npm-node-version: '--lts'
        method:
          - ''
          - 'script'
    steps:
      # For Ubuntu: install with packages directly
      - if: matrix.wsl-distrib != 'Debian'
        uses: Vampire/setup-wsl@v6
        with:
          distribution: ${{ matrix.wsl-distrib }}
          additional-packages: bash git curl ca-certificates wget

      # For Debian: install without packages first (apt-get update fails due to stale sources.list)
      # see https://github.com/Vampire/setup-wsl/issues/76
      - if: matrix.wsl-distrib == 'Debian'
        uses: Vampire/setup-wsl@v6
        with:
          distribution: ${{ matrix.wsl-distrib }}
      - if: matrix.wsl-distrib == 'Debian'
        shell: 'wsl-bash {0}'
        run: 'sed -i s/ftp.debian.org/archive.debian.org/ /etc/apt/sources.list'
      - if: matrix.wsl-distrib == 'Debian'
        name: 'Install packages with retries'
        shell: 'wsl-bash {0}'
        run: |
          retry() {
            local n=0
            local max=3
            local delay=5
            while true; do
              "$@" && break || {
                n=$((n+1))
                if [ $n -lt $max ]; then
                  echo "Command failed. Attempt $n/$max. Retrying in $delay seconds..."
                  sleep $delay
                else
                  echo "Command failed after $max attempts."
                  return 1
                fi
              }
            done
          }
          retry apt-get update
          retry apt-get upgrade --yes
          retry apt-get install --yes bash git curl ca-certificates wget

      - name: Retrieve nvm on WSL
        run: |
          if [ -z "${{ matrix.method }}" ]; then
            curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | bash
          else
            curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | METHOD="${{matrix.method}}" bash
          fi
          . "$HOME/.nvm/nvm.sh"
          nvm install ${{ matrix.npm-node-version }}
          node -v

  wsl_matrix_unofficial:
    continue-on-error: true
    name: 'WSL nvm install'
    defaults:
      run:
          shell: wsl-bash {0}
    runs-on: windows-latest
    env:
      WSLENV: NVM_INSTALL_GITHUB_REPO:NVM_INSTALL_VERSION:/p
      NVM_NODEJS_ORG_MIRROR: https://unofficial-builds.nodejs.org/download/release
    strategy:
      fail-fast: false
      matrix:
        wsl-distrib:
          - Alpine
        npm-node-version:
          - '--lts'
          - '21'
          - '18'
          - '16'
          - '14'
          - '12'
          - '11'
          - '10'
        method:
          - ''
          - 'script'
    steps:
      - uses: Vampire/setup-wsl@v6
        with:
          distribution: ${{ matrix.wsl-distrib }}
          additional-packages: bash git curl ca-certificates wget

      - name: Retrieve nvm on WSL
        run: |
          if [ -z "${{ matrix.method }}" ]; then
            curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | bash
          else
            curl -fsSLo- "https://raw.githubusercontent.com/${NVM_INSTALL_GITHUB_REPO}/${NVM_INSTALL_VERSION}/install.sh" | METHOD="${{matrix.method}}" bash
          fi
          . "$HOME/.nvm/nvm.sh"
          NVM_NODEJS_ORG_MIRROR=${{ env.NVM_NODEJS_ORG_MIRROR }} nvm install ${{ matrix.npm-node-version }}

  nvm_windows:
    name: 'tests, on windows'
    permissions:
      contents: none
    needs: [wsl_matrix, wsl_matrix_unofficial, cygwin_matrix, msys_matrix, msys_fail_install]
    runs-on: ubuntu-latest
    steps:
      - run: true