Docs

CI integration

Learn how to set up Acton checks, tests, and reports in CI pipelines

Set up CI by running the same Acton validation commands locally and in the pipeline: build, test, check, and fmt checks. Use the GitHub Actions and GitLab examples below as a starting point for contract-only projects and projects that also include a frontend.

The CI setup is ready when:

  • local validation commands pass;
  • GitHub Actions or GitLab pipelines exit successfully on a test commit;
  • lint findings appear as annotations in GitHub or as a Code Quality report in GitLab;
  • coverage uploads succeed when the coverage job is enabled.

Run the checks locally

Run the same commands locally before wiring them into CI:

acton build
acton test
acton check
acton fmt --check

These commands should exit with status 0.

If Acton is not installed on the host machine, run the same checks through the published Docker image:

docker run --rm \
  -v "$PWD":/workspace \
  -w /workspace \
  ghcr.io/ton-blockchain/acton:1.1.0 \
  build

Replace build with test, check, or fmt --check as needed.

Choose the lint output format

Use the lint output format that matches the CI system:

  • Default (or plain) output format prints diagnostics with source locations in the standard terminal output.
  • github prints GitHub workflow commands and creates annotations in GitHub Actions.
  • gitlab writes a GitLab Code Quality report (Code Climate style) and is the best default for GitLab CI.
  • sarif is useful when the pipeline uploads SARIF artifacts to GitHub code scanning or another SARIF consumer. In private GitHub repositories, use it only when code scanning is enabled for the repository.
  • json is useful for custom automation and editor integrations.

--fix works only with the default plain output format. With json, sarif, github, or gitlab, Acton rejects --fix instead of rewriting files.

To specify the format, use the --output-format flag. To specify the output file, use the --output-file flag.

For example, to write a SARIF file in CI, run:

acton check --output-format sarif --output-file .acton/reports/lint.sarif

JSON output

acton check --output-format json

This prints the linting report as a JSON object to stdout with:

  • success: true or false
  • diagnostics: array of diagnostics

Each diagnostic includes:

  • file as an absolute file path
  • severity, name, message, and optional code or help
  • annotations[] with 0-based range.start/end.{line,character}, is_primary, optional message, and optional tags
  • fixes[] with message, applicability (auto or manual), and structured edits[]

To print the exact JSON Schema of the report to stdout, run:

acton meta get-schema lint-report

Use JSON mode for editor integrations and custom tooling.

SARIF report

acton check --output-format sarif --output-file .acton/reports/lint.sarif

This creates a SARIF report in .acton/reports/lint.sarif.

The output includes:

  • SRCROOT-relative artifact locations when possible;
  • primary location and relatedLocations;
  • per-rule metadata such as docs helpUri, lifecycle status, and fixability;
  • structured SARIF fixes with Acton-specific applicability metadata.

Private GitHub repositories

GitHub shows uploaded SARIF files through code scanning. For private and internal repositories, SARIF upload works only when GitHub Code Security or GitHub Advanced Security is enabled for the repository. If it is not enabled, upload-sarif fails and the SARIF file will not create pull request annotations.

In that setup, keep SARIF only when another CI step or external tool consumes it. For GitHub pull request feedback without code scanning, use acton check --output-format github or an annotation layer such as reviewdog.

Set up GitHub Actions

Acton offers a GitHub action to set itself up. setup-acton downloads a release binary, restores and saves it with the GitHub Actions cache, adds acton to PATH, and exposes install details as outputs:

- name: Setup Acton
  uses: ton-blockchain/setup-acton@2d38fd579e1bf8753a3e0cff9ad695612b98a676 # v1.0.0
  id: setup-acton
  with:
    # (optional) Acton version to install.
    # Supported values include 'latest', a release tag such as 'v1.1.0',
    # a bare semantic version such as '1.1.0', or 'trunk'.
    # Defaults to [toolchain].acton in Acton.toml, then 'latest'.
    version: '1.1.0'

    # (optional) Target architecture.
    # Supported values: x86_64, aarch64.
    # Auto-detected from the runner if not specified.
    architecture: 'x86_64'

    # (optional) Target platform.
    # Supported values: linux, apple, windows.
    # Auto-detected from the runner if not specified.
    platform: 'linux'

    # (optional) Working directory for the Acton project.
    # Used when reading Acton.toml. Defaults to the GitHub workspace.
    working-directory: ${{ github.workspace }}

    # (optional) Restore and save the resolved Acton binary with the
    # GitHub Actions cache. Defaults to true.
    save-cache: true

    # (optional) GitHub token.
    # Used for authenticated release metadata and asset downloads.
    # Defaults to the current github.token value.
    github-token: ${{ github.token }}

# The setup action produces the following outputs: acton-path, acton-version, and cache-hit.
- run: |
    # acton-path contains full path to the installed Acton binary.
    echo "Path: ${{ steps.setup-acton.outputs.acton-path }}"

    # acton-version contains installed Acton version parsed from `acton --version`.
    # If the version cannot be detected, acton-version returns 'unknown'.
    echo "Version: ${{ steps.setup-acton.outputs.acton-version }}"

    # cache-hit is true when the binary was restored from the Actions cache.
    echo "Cache hit: ${{ steps.setup-acton.outputs.cache-hit }}"

If version is omitted, setup-acton reads [toolchain].acton from Acton.toml in working-directory; if no project version is configured, it installs the latest release:

Acton.toml
[toolchain]
acton = "1.1.0"

The action accepts versioned releases, latest, trunk, and custom release tags. Pin a versioned release in Acton.toml or in the version input for reproducible workflows. Use trunk only for preview workflows.

Caching is enabled by default. The cache key includes the binary name, resolved version, platform target, and architecture, and the post-step saves the cache only after a successful job. When version: 'trunk' is used, the action skips saving the cache because trunk is a moving target.

For a contract-only repository, create .github/workflows/contracts.yml:

.github/workflows/contracts.yml
name: Contracts

on:
  push:
    # Keep the primary protected branch:
    branches:
      - main
      - master
  pull_request:
    branches:
      - main
      - master
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

permissions: { }

jobs:
  build-and-test:
    name: Build and Test
    runs-on: ubuntu-latest

    permissions:
      contents: read

    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false

      - name: Setup Acton
        uses: ton-blockchain/setup-acton@2d38fd579e1bf8753a3e0cff9ad695612b98a676 # v1.0.0

      - name: Build
        run: acton build

      - name: Formatter
        run: acton fmt --check

      - name: Linter
        run: acton check --output-format github

      - name: Test
        run: acton test
  • The acton check --output-format github command emits workflow annotations directly in the GitHub Actions log and pull request checks.

  • The acton check command exits with a non-zero status when it reports at least one error, or when warning count exceeds max-warnings. To fail CI on any warning, set:

    Acton.toml
    [lint]
    max-warnings = 0

Add coverage reporting

Acton can generate lcov output directly from the test runner. Add this to a GitHub Actions job that uploads coverage to Codecov:

.github/workflows/coverage.yml
name: Coverage

on:
  pull_request:
    branches:
      # Keep the primary protected branch:
      - main
      - master

permissions: {}

jobs:
  coverage:
    runs-on: ubuntu-latest

    permissions:
      contents: read

    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false

      - name: Setup Acton
        uses: ton-blockchain/setup-acton@2d38fd579e1bf8753a3e0cff9ad695612b98a676 # v1.0.0

      - name: Run tests with coverage
        run: acton test --coverage --coverage-format lcov --coverage-file lcov.info

      - name: Upload coverage
        uses: codecov/codecov-action@v6
        with:
          files: lcov.info
          token: ${{ secrets.CODECOV_TOKEN }}

To fail the job when coverage drops below a threshold, add --coverage-minimum-percent <PERCENT> to the test command, where <PERCENT> is a number from 0 to 100. Alternatively, set the default value in the manifest:

Acton.toml
[test.coverage]
minimum-percent = 50

Add frontend checks

If the repository also contains a frontend created with acton new --app or a custom one, create a separate frontend workflow with Node.js setup and validation steps. Keep Acton installed in this job when the frontend build can call acton build, as the generated contract-aware app templates do.

.github/workflows/dapp.yml
name: dApp

on:
  push:
    # Keep the primary protected branch:
    branches:
      - main
      - master
  pull_request:
    branches:
      - main
      - master
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

permissions: {}

jobs:
  build-and-test:
    name: Build and Test
    runs-on: ubuntu-latest

    permissions:
      contents: read

    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false

      - name: Setup Acton
        uses: ton-blockchain/setup-acton@2d38fd579e1bf8753a3e0cff9ad695612b98a676 # v1.0.0

      - name: Setup Node
        uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
        with:
          node-version: 22
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Formatter
        run: npm run fmt:check

      - name: Typecheck
        run: npm run typecheck

      - name: Build
        run: npm run build

      - name: Test
        run: npm run test

Set up GitLab CI

For GitLab, run Acton from the published Docker image. The example pins the image to 1.1.0; use latest only if the pipeline should always follow the newest release.

.gitlab-ci.yml
image:
  name: ghcr.io/ton-blockchain/acton:1.1.0
  entrypoint: [""]

stages:
  - validate

validate:
  stage: validate
  script:
    - acton --version
    - acton build
    - acton fmt --check
    - acton check --output-format gitlab --output-file gl-code-quality-report.json
    - acton test
  artifacts:
    when: always
    reports:
      codequality: gl-code-quality-report.json

The entrypoint: [""] override is required because the Acton Docker image uses acton as its entrypoint, while GitLab Runner expects to run job scripts through a shell. acton check --output-format gitlab writes a Code Quality report that GitLab can show directly in merge requests.

Store secrets and wallet mnemonics

Validation jobs do not need to set up wallets. For noninteractive deployment jobs, use mnemonic-env to store and retrieve mnemonics:

wallets.toml
[wallets.deployer]
kind = "v5r1"
keys = { mnemonic-env = "DEPLOYER_MNEMONIC" }

Then expose the secret in CI:

env:
  DEPLOYER_MNEMONIC: ${{ secrets.DEPLOYER_MNEMONIC }}

In GitLab CI, store DEPLOYER_MNEMONIC as a masked protected variable with the same name.

Never commit mnemonic phrases, plaintext wallet files, or .env files that contain production secrets.

Last updated on

On this page