Skip to content

v1.0.5 — the GitLab recipe runs on a CI runner, and the merge request carries only translations

Latest

Choose a tag to compare

@pavel-te pavel-te released this 31 Aug 09:27
3521751

The GitLab recipe we print could not translate anything on an actual GitLab runner. Everything here was found by running the recipe exactly as printed, on a detached HEAD, rather than by reading it.

The recipe never reached the API

A CI runner checks out a detached HEAD. There, git branch --show-current succeeds and prints an empty string — so the || fallbacks in get_current_branch were never reached, and validate_args rejected the empty file tag before a single request went out.

recipe as printed:            EXIT=1   on disk: en.json            <- nothing translated
same, with --file-tag-name:   EXIT=0   on disk: de.json en.json fr.json

An empty answer is now treated as no answer: the runner's own branch variable is consulted (CI_COMMIT_REF_NAME, GITHUB_REF_NAME, BITBUCKET_BRANCH, BRANCH_NAME, CIRCLE_BRANCH), then main. That fixes the printed recipe, the standalone snippet, and every other CI whose checkout is detached — Bitbucket Pipelines and the Jenkins git plugin included.

The merge request carried the CLI itself

The recipe curled ptc-cli.sh into the project root and ran git add -A, so every merge request contained the script plus whatever an earlier job step had dirtied:

what it committed:   .ptc-config.yml  dist/bundle.js  locales/de.json  package-lock.json  ptc-cli.sh
what it should:      locales/de.json

And because that download was always a new file, git diff --cached --quiet never short-circuited — each run force-updated the merge request even when no translation had changed.

The download now goes to /tmp, and a new flag records what the run actually wrote:

--written-manifest FILE    every written path, NUL-separated, repository-root-relative

which the recipe hands to git add --pathspec-from-file=FILE --pathspec-file-nul. git reads the file itself, so the recipe needs no arrays and no word splitting — its shell is busybox sh, since alpine has no bash until before_script installs it.

Two behaviours shaped that design, both verified in alpine:3.22 (git 2.49.1): an ignored path in the manifest makes git add exit 1 while still staging the rest, so the recipe needs || true or GitLab aborts the job; and a path holding a glob metacharacter stages the wrong file — messages[1].json also staged the caller's messages1.json — unless written as :(literal).

The unpack filter dropped documented file types

find "$dir" -type f -name "*.json" -o -name "*.po" -o ...

-o binds looser than the implicit -a, so -type f applied only to the first -name: a directory named *.po matched and was moved wholesale. The alternatives are now grouped, and the list covers what the docs promise — .php and .properties were both documented and both silently never reached disk. .xml, .strings and .resx are covered too.

[skip ci] was the wrong loop guard

GitLab honours it by creating no pipeline at all. That silenced the translation merge request's own pipeline — leaving the translations untested and, with "Pipelines must succeed" enabled, unmergeable — and a squash carried the marker into the default branch, silencing the whole project. The guard moved to rules:, which GitLab evaluates against the commit message without suppressing anything.

How this was checked

tests/test-ci-recipe.sh runs the printed recipe end to end against a mock PTC API, with only curl and git push shimmed, and asserts what the merge request would contain: translation on a detached HEAD; only translations committed, with the fixture dirtying dist/bundle.js and package-lock.json first; the CLI neither committed nor left behind; no push when a second identical run writes nothing; and the shape of the push itself.

The detached-HEAD behaviour is now pinned by a test that previously documented it as a known defect.

Verifying the download

sha256  d5b1b2c62c530f43d76aa924e399548379369e458955a31bd11539580d71428d  ptc-cli.sh
curl -fsSL https://raw.githubusercontent.com/OnTheGoSystems/ptc-cli/v1.0.5/ptc-cli.sh -o ptc-cli.sh
shasum -a 256 ptc-cli.sh    # sha256sum on Linux

9 suites, 0 failures, on bash 3.2 (macOS) and on current bash (Linux).

v1 points here. v1.0.4 and earlier are unchanged if you pin them.