Files
actions/pnpm-install/README.md
T
cierzniak e8cc842238 feat: add pnpm-install as a shared composite action
Lifts ptpa_pl's local .gitea/actions/pnpm-install into this repo, parametrised
enough for repositories we have not met yet: working-directory, install args,
pnpm version and an opt-in store cache.

Cache is off by default. ADR-0014 pins actions/cache to major 3 and no workflow
on this instance has exercised the cache server yet - a shared action that a
dozen jobs hang off is the wrong place to premiere that dependency.

Two traps found while testing against ptpa_pl's lockfile in node:24-bookworm-slim,
both avoided by pinning the store instead of reading `pnpm store path`:
that command defaults to <workspace>/.pnpm-store, inside the working tree where a
committing job could sweep it up, and it exits 0 while printing its error to
stdout, which would have fed actions/cache a garbage path silently.

The version input also carries COREPACK_ENABLE_PROJECT_SPEC=0, without which a
packageManager field outranks `corepack prepare --activate` and the input would
do nothing at all - no effect, no error.
2026-08-10 23:32:51 +02:00

5.2 KiB

pnpm-install

Aktywuje pnpm przez corepack i instaluje zależności z lockfile'a.

      - uses: actions/checkout@v7
      - uses: https://git.cierzniak.it/gitea-runner/actions/pnpm-install@v1
      - run: pnpm run lint:js

Podprojekt w monorepo, z cache'em store'a:

      - uses: https://git.cierzniak.it/gitea-runner/actions/pnpm-install@v1
        with:
          working-directory: ./wizard
          cache: 'true'

args zastępuje całą listę flag, więc --frozen-lockfile trzeba powtórzyć:

      - uses: https://git.cierzniak.it/gitea-runner/actions/pnpm-install@v1
        with:
          args: --frozen-lockfile --ignore-scripts

Wejście

Input Wymagany Domyślnie Co to
working-directory nie . Katalog z package.json i pnpm-lock.yaml
version nie — Wersja pnpm. Pusta bierze ją z pola packageManager; podana nadpisuje to pole
args nie --frozen-lockfile Pełna lista argumentów pnpm install
cache nie false 'true' cache'uje store pnpm między jobami

Outputów nie ma.

Node i corepack pochodzą z obrazu joba — akcja nie stawia żadnego z nich. Sprawdzone na git.cierzniak.it/gitea-runner/node:24 (Node 24.18.1, corepack 0.35.0).

Dlaczego tak

args to jeden input, nie frozen-lockfile plus extra-args. Kto go podaje, przejmuje całą listę flag. Dwa inputy wymagałyby reguły, co się dzieje przy frozen-lockfile: true i args: --no-frozen-lockfile — tu takiego stanu nie ma.

Wersja pnpm domyślnie z packageManager. To pole jest już źródłem prawdy dla corepacka lokalnie, a wpisanie jej drugi raz do workflow tworzy dwa źródła, które rozjeżdżają się po pierwszym bumpie. Input version jest przede wszystkim dla repozytoriów bez tego pola — bez niego samo corepack enable nie ma czego aktywować.

version dokłada COREPACK_ENABLE_PROJECT_SPEC=0, bo inaczej nic by nie robił. Samo corepack prepare pnpm@X --activate ustawia tylko wersję domyślną, do której corepack sięga przy braku packageManager; obecne pole ją przebija. Sprawdzone: w projekcie z packageManager: pnpm@9.15.9 po prepare pnpm@10.20.0 --activate dalej odpowiada 9.15.9 (COREPACK_ENABLE_STRICT=0 też nie pomaga — dopiero COREPACK_ENABLE_PROJECT_SPEC=0 daje 10.20.0). Bez tego input byłby cichym no-opem: ustawiasz, nic się nie zmienia, zero błędu. Cena jest taka, że przy podanym version pole packageManager przestaje obowiązywać — dlatego zostawiaj go pustym wszędzie, gdzie to pole istnieje.

Cache jest opt-in i domyślnie wyłączony. ADR-0014 trzyma actions/cache na majorze 3, bo od v4.2 akcja mówi protokołem cache service v2, którego Gitea nie implementuje (go-gitea#33393). Akcja wymaga też skonfigurowanego serwera cache'a — kontener joba i kontener runnera siedzą w różnych przestrzeniach sieciowych, więc bez tego zwraca ETIMEDOUT. Runnery tej instancji mają cache.enabled: true i external_server, ale żaden workflow jeszcze z tego nie korzystał. Domyślnie wyłączony cache pozwala to sprawdzić na jednym repo, zamiast robić premierę na wszystkich naraz.

Klucz cache'a liczy sha256sum, nie hashFiles(). hashFiles to funkcja natywna GitHuba i jej zachowanie w act_runner byłoby kolejną niewiadomą dokładaną do i tak niesprawdzonego tutaj actions/cache. Do tego sklejanie ścieżki z working-directory daje wzorce w rodzaju .//pnpm-lock.yaml. sha256sum jest w każdym obrazie z gitea-runner/images i widać w logu, co policzył. runner.os w kluczu idzie za wzorcem oficjalnej pnpm/action-setup.

Store jest przypięty do ~/.pnpm-store, zamiast odczytany z pnpm store path. Dwa powody, oba sprawdzone w obrazie node:24-bookworm-slim:

  1. Domyślnie store ląduje w <workspace>/.pnpm-store/v3, czyli w drzewie roboczym — pnpm celowo szuka miejsca na tym samym systemie plików co projekt, a /workspace jest bind-mountem. Job, który commituje (jak check-pchia w ptpa_pl), ma tam minę.
  2. pnpm store path przy błędzie kończy się kodem 0 i wypisuje błąd na stdout (EROFS: read-only file system…). path= w GITHUB_OUTPUT dostałoby wtedy śmieci, a actions/cache cache'owałby nieistniejącą ścieżkę — po cichu, bez czerwonego joba.

Przestawia go wyłącznie npm_config_store_dir; PNPM_STORE_DIR nie jest ustawieniem pnpm i nie działa. Zmienna leci przez $GITHUB_ENV, żeby dosięgła też kroku instalacji, i tylko przy włączonym cache — przy cache: false rozmieszczenie store'a zostaje takie, jakie pnpm wybiera dziś, więc obecni konsumenci nic nie odczuwają.

Cache obejmuje ~/.pnpm-store, a nie podkatalog z wersją, bo ten zależy od majora pnpm — sprawdzone: v3 przy pnpm 9, v10 przy pnpm 10.

Akcja obsługuje wyłącznie pnpm. Wariant wykrywający lockfile i wołający npm albo yarn rozmyłby kontrakt na trzy ścieżki o różnych flagach, różnym modelu cache'a i różnych trybach błędu — z czego dwie nikt by nie testował. Gdy npm będzie potrzebny, dostanie osobną akcję.