name: Test Action on: pull_request: push: branches: - master workflow_dispatch: jobs: smoke: # Cross-OS coverage. Exercises the bootstrap install + PATH on each platform, # the version-respects-request regression (#225 / #230 — Windows PATH shadow), # and the bin_dest output regression (#247). Multi-version coverage on Linux # so we don't pay 3x for major-version differences. name: 'Smoke (${{ matrix.name }})' runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: include: - name: 'ubuntu / v9.15.5' os: ubuntu-latest version: '9.15.5' - name: 'ubuntu / v10.33.0' os: ubuntu-latest version: '10.33.0' - name: 'ubuntu / v9.15.5 / custom-dest' os: ubuntu-latest version: '9.15.5' dest: '~/test/pnpm' - name: 'macos / v9.15.5' os: macos-latest version: '9.15.5' - name: 'windows / v9.15.5' os: windows-latest version: '9.15.5' steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - id: pnpm name: Run the action uses: ./ with: version: ${{ matrix.version }} dest: ${{ matrix.dest || '~/setup-pnpm' }} - name: 'Test: pnpm/pnpx on PATH report the requested version (incl. via bin_dest)' # Pass paths via env, not template interpolation, so Windows # backslashes in `bin_dest` aren't eaten by bash's escape handling. env: BIN_DEST: ${{ steps.pnpm.outputs.bin_dest }} REQUIRED: ${{ matrix.version }} run: | set -e which pnpm which pnpx actual="$(pnpm --version)" echo "pnpm --version: ${actual}" if [ "${actual}" != "${REQUIRED}" ]; then echo "Expected pnpm version ${REQUIRED}, but got ${actual}" exit 1 fi bin_dest_version="$("$BIN_DEST/pnpm" --version)" echo "bin_dest pnpm --version: ${bin_dest_version}" if [ "${bin_dest_version}" != "${REQUIRED}" ]; then echo "Expected ${REQUIRED} via bin_dest, but got ${bin_dest_version}" exit 1 fi shell: bash - name: 'Test: install in a fresh project' run: | mkdir /tmp/test-project cd /tmp/test-project pnpm init pnpm add is-odd shell: bash manifest_pin: # Folds the old test_package_manager_field, test_dev_engines, and # test_dev_engines_on_fail_error jobs. The action's manifest handling is # OS-independent, so ubuntu-only is sufficient. name: 'Manifest pin: ${{ matrix.label }}' runs-on: ubuntu-latest strategy: fail-fast: false matrix: include: - label: 'packageManager pnpm@9.15.5 (#227)' manifest: '{"packageManager":"pnpm@9.15.5"}' version: '9.15.5' - label: 'packageManager pnpm@10.33.0' manifest: '{"packageManager":"pnpm@10.33.0"}' version: '10.33.0' - label: 'devEngines onFail=download, exact' manifest: '{"devEngines":{"packageManager":{"name":"pnpm","version":"9.15.5","onFail":"download"}}}' version: '9.15.5' - label: 'devEngines onFail=download, range' manifest: '{"devEngines":{"packageManager":{"name":"pnpm","version":">=9.15.0","onFail":"download"}}}' version: '>=9.15.0' - label: 'devEngines onFail=error, exact (#252)' manifest: '{"devEngines":{"packageManager":{"name":"pnpm","version":"9.15.5","onFail":"error"}}}' version: '9.15.5' - label: 'devEngines onFail=error, range (#252)' manifest: '{"devEngines":{"packageManager":{"name":"pnpm","version":">=9.15.0","onFail":"error"}}}' version: '>=9.15.0' - label: 'explicit version: pnpm_config_pm_on_fail not exported' # Regression guard for the af8e203 scope fix: when the user passes an # explicit `version:` input, the action must NOT export # pnpm_config_pm_on_fail=download, so the user's strict onFail policy # is preserved. Asserted directly on the env var rather than pnpm # runtime behavior — different pnpm majors read devEngines # differently (v10 ignores it, v11+ honors it). manifest: '{"devEngines":{"packageManager":{"name":"pnpm","version":"9.15.5","onFail":"error"}}}' explicit_version: '10.33.0' expect_pm_on_fail_unset: true steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Set up package.json run: echo '${{ matrix.manifest }}' > package.json shell: bash - name: Run the action uses: ./ with: version: ${{ matrix.explicit_version }} - name: 'Test: pnpm reports the pinned version' if: ${{ !matrix.expect_pm_on_fail_unset }} env: REQUIRED: ${{ matrix.version }} run: | set -e actual="$(pnpm --version)" echo "pnpm version: ${actual}" if [ "${REQUIRED}" = ">=9.15.0" ]; then min="9.15.0" if [ "$(printf '%s\n' "${min}" "${actual}" | sort -V | head -n1)" != "${min}" ]; then echo "Expected pnpm version >= ${min}, but got ${actual}" exit 1 fi else if [ "${actual}" != "${REQUIRED}" ]; then echo "Expected pnpm version ${REQUIRED}, but got ${actual}" exit 1 fi fi shell: bash - name: 'Test: pnpm_config_pm_on_fail not exported (explicit version preserves strict policy)' if: ${{ matrix.expect_pm_on_fail_unset }} run: | if [ -n "${pnpm_config_pm_on_fail:-}" ]; then echo "Expected pnpm_config_pm_on_fail to be unset, but got: '${pnpm_config_pm_on_fail}'" exit 1 fi echo "pnpm_config_pm_on_fail is unset, as expected" shell: bash standalone: name: Standalone mode runs-on: ubuntu-latest steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Run the action uses: ./ with: version: 9.15.0 standalone: true - name: 'Test: pnpm works' run: | set -e which pnpm actual="$(pnpm --version)" if [ "${actual}" != "9.15.0" ]; then echo "Expected 9.15.0, got ${actual}" exit 1 fi mkdir /tmp/test-standalone cd /tmp/test-standalone pnpm init pnpm add is-odd shell: bash standalone_windows_self_update: # Regression guard for the patchPnpmEnv PATH-shadow bug. When # standalone: true on Windows AND the requested pnpm differs from the # bootstrap, the previous patchPnpmEnv prepended node_modules/.bin to # PATH; that directory contains an npm-created pnpm.cmd shim pointing # at the BOOTSTRAP pnpm, which shadowed the self-updated pnpm at # $PNPM_HOME/bin and caused `pnpm install` inside the action to run # under the bootstrap version. Exercising a newer-pnpm-only flag # (`--no-runtime`, added in 11.1.0) makes the regression assertable: # if the bootstrap (11.0.4) handles the install, it errors with # "Unknown option: 'runtime'". name: 'Standalone Windows self-update (PATH regression)' runs-on: windows-latest steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Set up package.json with a minimal manifest # run_install needs a manifest to install against. Removing the # repo's existing pnpm-lock.yaml avoids frozen-lockfile mismatch. run: | rm -f pnpm-lock.yaml echo '{"name":"sw","private":true,"packageManager":"pnpm@11.1.0"}' > package.json shell: bash - name: Run the action uses: ./ with: version: 11.1.0 standalone: true run_install: | args: ['--no-runtime'] - name: 'Test: pnpm install completed under the self-updated pnpm' # If the bug recurs, the previous step's run_install will have failed # the job with "Unknown option: 'runtime'", so reaching this step # implies success. Still verify the version on PATH matches request. env: REQUIRED: '11.1.0' run: | set -e actual="$(pnpm --version)" echo "pnpm --version: ${actual}" if [ "${actual}" != "${REQUIRED}" ]; then echo "Expected pnpm ${REQUIRED}, got ${actual}" exit 1 fi shell: bash cache_store_path: # Regression guard for #233. When package.json pins a pnpm major that # differs from the bootstrap pnpm's major, the bootstrap reports its # own STORE_VERSION from `pnpm store path` (the `store` command skips # pnpm's auto-switch). The user's actual `pnpm install` runs under the # pinned version and writes to a different STORE_VERSION, so the post # step's saveCache then fails with "Path Validation Error". The fix is # to self-update the bootstrap to the pinned version up front. name: 'Cache store path matches install (#233): ${{ matrix.label }}' runs-on: ubuntu-latest strategy: fail-fast: false matrix: include: - label: 'packageManager pnpm@10.33.0' manifest: '{"packageManager":"pnpm@10.33.0","dependencies":{"is-odd":"3.0.1"}}' - label: 'devEngines exact pnpm@10.33.0' manifest: '{"devEngines":{"packageManager":{"name":"pnpm","version":"10.33.0"}},"dependencies":{"is-odd":"3.0.1"}}' - label: 'devEngines range >=10 <11' manifest: '{"devEngines":{"packageManager":{"name":"pnpm","version":">=10 <11"}},"dependencies":{"is-odd":"3.0.1"}}' steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Set up package.json run: echo '${{ matrix.manifest }}' > package.json shell: bash - id: pnpm uses: ./ with: cache: true run_install: | - args: [--no-frozen-lockfile] - name: 'Test: store path computed by the action exists on disk' run: | set -e actual="$(pnpm store path --silent)" echo "pnpm store path: ${actual}" if [ ! -d "${actual}" ]; then echo "Expected store path to exist on disk; cache save would fail" exit 1 fi shell: bash run_install: name: 'run_install (${{ matrix.run_install.name }})' runs-on: ubuntu-latest strategy: fail-fast: false matrix: run_install: - name: 'null' value: 'null' - name: 'global' value: | args: - --global - --global-dir=./pnpm-global - npm - yarn steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Run the action uses: ./ with: version: 9.15.5 run_install: ${{ matrix.run_install.value }} - name: 'Test: pnpm works' run: | set -e which pnpm which pnpx actual="$(pnpm --version)" if [ "${actual}" != "9.15.5" ]; then echo "Expected 9.15.5, got ${actual}" exit 1 fi shell: bash