Skip to content

CI CD templates

Pavel Tkachenko edited this page Aug 6, 2026 · 2 revisions

CI/CD templates

./ptc-cli.sh init detects your provider and prints one of these, already pinned to the CLI version you ran it with. The copies here are the same recipes with two refinements it does not print: a paths: trigger on the GitHub side and a sha256sum check on the GitLab side. Both are called out where they appear.

Both recipes are loop-safe without those refinements: the translation result lands on a stable ptc/translations branch as a pull/merge request, and that branch is not a trigger branch, so a translation commit cannot start another translation run.


GitHub Actions

Use the action — OnTheGoSystems/ptc-action. It vendors ptc-cli inside itself, so nothing is downloaded at job time, and it SHA-pins the action that opens the PR.

Before the first run

  1. Settings → Secrets and variables → Actions → add PTC_API_TOKEN.
  2. Settings → Actions → General → Workflow permissions → enable "Allow GitHub Actions to create and approve pull requests". Skipping this is the single most common first-run failure.

.github/workflows/translate.yml:

name: Translate
on:
  push:
    branches: [main]
    paths: ['locales/en.json']   # your SOURCE files — a second guard, see below
  workflow_dispatch: {}

permissions:
  contents: write
  pull-requests: write

jobs:
  translate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: OnTheGoSystems/ptc-action@v1
        with:
          api-token: ${{ secrets.PTC_API_TOKEN }}
          create-pr: true

api-token is the only input you must pass. A .ptc-config.yml committed at the repository root is picked up on its own; with no config at all the action runs ptc init and translates what it detects. (ptc init prints this workflow with an explicit config-file: and without the paths: trigger — the trigger above narrows the runs to source changes, which is worth keeping.)

Worth adding: pr-token: ${{ secrets.PTC_PR_TOKEN }}, a PAT or GitHub App token, so the translation PR triggers your own checks — a PR opened with the default GITHUB_TOKEN does not.

Full input list: action README.


GitLab CI

There is no CI/CD Catalog component, and there cannot be one: include: component: is resolved against your GitLab instance, so a component published on someone else's server can never be included from yours. Paste the job instead.

Before the first run

  1. Settings → CI/CD → Variables → add PTC_API_TOKEN as a masked variable. It is read from the environment and never appears on the command line.
  2. Give the job a way to push — see the note under the snippet.

Append to .gitlab-ci.yml:

ptc-translate:
  stage: deploy
  image: alpine:3.22
  rules:
    - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
  before_script:
    - apk add --no-cache bash curl git unzip
  script:
    - curl -fsSL https://raw.githubusercontent.com/OnTheGoSystems/ptc-cli/v1.0.3/ptc-cli.sh -o ptc-cli.sh
    # `ptc init` does not print this line; add it and you get the same integrity
    # guarantee the GitHub action gets from vendoring the script.
    - echo "87efed00bd9345b9a4d5fb1972d8d53525246f6a2a4e6a48ae7d20d67e41362a  ptc-cli.sh" | sha256sum -c -
    - chmod +x ptc-cli.sh
    - ./ptc-cli.sh --config-file .ptc-config.yml
    - |
      if ! git diff --quiet; then
        git config user.email "ci@ptc"
        git config user.name "PTC Translate"
        git checkout -B ptc/translations
        git add -A
        git commit -m "chore(i18n): update translations via PTC [skip ci]"
        git push -o merge_request.create \
                 -o merge_request.target="$CI_DEFAULT_BRANCH" \
                 -o merge_request.title="Update translations from PTC" \
                 -f "https://gitlab-ci-token:${PTC_GIT_PUSH_TOKEN:-$CI_JOB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" HEAD:ptc/translations
      fi

The push needs a token that may write to the repository. Two routes, pick whichever your instance and plan allow:

  • CI_JOB_TOKEN — works only if a maintainer enables Settings → CI/CD → Job token permissions → "Allow Git push requests to the repository". GitLab 18.4 or later; off by default. Not possible at all before 18.4.
  • PTC_GIT_PUSH_TOKEN — a project access token with the write_repository scope, stored as a masked CI/CD variable. Project access tokens are not available on gitlab.com Free.

The snippet reads PTC_GIT_PUSH_TOKEN and falls back to CI_JOB_TOKEN, so the same job works either way.

The commit carries [skip ci] — the only skip token GitLab honours. [skip translations] and similar do nothing here.

Alpine note: a bare alpine:3.22 has no bash and no curl, which is what the before_script is for. git is installed for the push step at the end of the job, not for the CLI — every call the CLI makes to git is guarded and falls back. jq is never invoked at all; it used to be on this line and is not needed. unzip unpacks the downloaded translations: alpine already provides it as a busybox applet, so it is named only to keep the job working if you swap the image for one that does not.


Pinning and verification

Latest release v1.0.3
sha256 of ptc-cli.sh 87efed00bd9345b9a4d5fb1972d8d53525246f6a2a4e6a48ae7d20d67e41362a

Pin an exact tag (v1.0.3) for a build that never changes, or the floating v1 tag to pick up backward-compatible updates. Never fetch from refs/heads/main — that is a moving branch, and a push to it would change what your build runs.

Checksums for every release are on the releases page.

Clone this wiki locally