actrun

repository·main·Indexed 20 days ago

https://github.com/mizchi/actrun

A local GitHub Actions runner built with MoonBit that allows developers to run and debug workflows locally. It supports WASM actions via WASI-compatible modules (Rust, Go, MoonBit, C), provides multiple workspace modes (local, worktree, tmp, docker), and integrates with various container runtimes including Docker, Podman, and Lima. Features include workflow linting, dependency graph visualization, and the ability to run only affected workflows based on file patterns.

Tokens
28K
Snippets
98
Records
137
Agent score
70%

What's inside actrun

  1. Overview of actrun

    main

    actrun is a core API designed for MVP-compatible GitHub Actions push CI runners. It parses a subset of GitHub Actions push workflows, lowers them into a bitflow Intermediate Representation (IR), and executes them on the host shell for native targets.

    Key capabilities include:

    • Parsing push trigger filters and workflow YAML subsets.
    • Handling strategy.matrix (axes, include, exclude, fail-fast, max-parallel).
    • Managing job dependencies (needs) and aggregated outputs/results.
    • Supporting minimal if: conditions at both job and step levels.
    • Providing minimal support for ${{ vars.* }} and ${{ secrets.* }} via ACTRUN_VAR_<NAME> and ACTRUN_SECRET_<NAME> environment variables.
    • Supporting reusable workflows (workflow_call), local/remote uses, and container-based jobs (including Docker adapters and service containers).
    • Implementing built-in actions like actions/checkout, actions/upload-artifact, actions/download-artifact, actions/setup-node, and actions/cache.
    • Managing a local run store for logs, artifacts, and caches.
  2. Understand the precedence of GitHub context values

    main

    When actrun resolves GitHub context values (like github.repository or github.ref_name), it follows a specific order of precedence. Higher priority sources will override lower ones:

    1. CLI flags: Explicit flags like --repository, --ref, --before, and --after.
    2. Event payload: The JSON file provided via the --event <path> flag.
    3. actrun.toml: Values defined under the [local_context] table.
    4. Local git auto-detection: Automatic detection from the current git repository.

    [local_context] in your configuration file only fills in missing values; it will not overwrite values already provided by CLI flags or an event payload.

  3. Understand how custom registry actions are resolved

    main

    actrun supports custom registry protocols via parse_action_ref. A custom registry action using the bit:// scheme (e.g., bit://std/cache@v1) resolves its manifest from a local directory structure defined by the ACTRUN_ACTION_REGISTRY_ROOT environment variable.

    The resolution pattern is: ACTRUN_ACTION_REGISTRY_ROOT/<scheme>/<name>/<version>

  4. Optimize Node actions with WASM sidecars (Provisional)

    main

    On actrun self-hosted runners, you can optimize standard node* actions by providing a .wasm sibling to the runs.main file. The runner will automatically detect and use the WASM file for execution.

    Discovery Rule (Provisional): If dist/index.js is defined as the main entry point, the runner looks for dist/index.wasm in the same directory.

    Note: This is a provisional ecosystem contract and naming conventions may change in future releases.

    File structure example:
    - dist/index.js
    - dist/index.wasm
  5. Use conditional steps for local vs remote execution

    main

    You can control whether a step runs locally (via actrun) or on GitHub Actions by using the ACTRUN_LOCAL environment variable in your workflow's if: condition. actrun automatically sets ACTRUN_LOCAL=true.

    steps:
      # Skip locally (runs on GitHub Actions)
      - uses: actions/checkout@v5
        if: ${{ !env.ACTRUN_LOCAL }}
    
      # Run only locally (skips on GitHub Actions)
      - run: echo "debug"
        if: ${{ env.ACTRUN_LOCAL }}
  6. Use Nix for environment management

    main

    actrun integrates with Nix to provide dependencies. It auto-detects flake.nix or shell.nix by default.

    • --no-nix: Disable Nix wrapping.
    • --nix-packages "<packages>": Provide ad-hoc Nix packages without a flake.
    • ACTRUN_NIX=false: Environment variable to disable Nix.

    Configuration (actrun.toml):

    • nix_mode = "<mode>"
    • nix_packages = ["package1", "package2"]
    # Ad-hoc nix packages
    actrun ci.yml --nix-packages "python312 jq"
  7. Run workflows based on affected files

    main

    Use the --affected flag to only run a workflow if relevant files have changed since the last successful run. You can also compare against a specific git revision.

    • --affected: Run if relevant files changed since last success.
    • --affected <revision>: Compare against a specific revision (e.g., HEAD~3 or a commit SHA).

    Configuration: To define what files are 'relevant' for a workflow, use the [affected.<workflow-file>] section in actrun.toml with a patterns array. If not configured, it falls back to the on:push:paths defined in the workflow file itself.

    # Only run if relevant files changed since last success
    actrun ci.yml --affected
    
    # Compare against a specific revision
    actrun ci.yml --affected HEAD~3
  8. Understand the WASM Container contract

    main

    The WASM Container is a minimal, portable CI foundation designed to replace heavy, language-specific runtimes with a strict WASI-based execution model. It uses wasmtime as the only runtime and bash + coreutils for shell logic.

    Key Constraints:

    • No Node.js: You cannot use uses: actions/* or any Node-based local actions.
    • No Docker-in-Docker: You cannot use uses: docker://.
    • WASI-only: Tools must be compiled to .wasm (e.g., from Rust, Go, C, or MoonBit) to be used via the wasm:// protocol.
    • Git Support: git is available for checkout and workspace operations.

    Capabilities Summary:

    CapabilityAvailableNotes
    run: stepsYesbash + coreutils for glue logic
    uses: wasm://Yeswasmtime (WASI) for compiled modules
    uses: actions/*NoNo Node.js runtime
    uses: docker://NoNo container runtime
    uses: ./localComposite onlyNo node/docker local actions
    gitYesFor checkout/workspace
  9. Understand the actrun Public API contract

    main

    actrun's release contract is designed to align as closely as possible with existing GitHub Actions expressions. The project distinguishes between a Stable surface (compatible with GitHub Actions) and Experimental/Internal extensions.

    Key principles:

    • Compatibility: actrun promises a GitHub-compatible workflow and action surface.
    • WASM Support: WASM support is provided as an optimization for self-hosted runners.
    • Fallback: For actions using WASM, GitHub-hosted runners are guaranteed to fall back to standard JavaScript execution if the WASM optimization is unavailable.
  10. Use bitflow task caching with actrun

    main

    When using bitflow IR, you can integrate task caching into your runs using --flow-cache-store and --flow-signature.

    • Dry-run: Using these flags allows actrun to calculate the bitflow task cache plan. The plan is included in the --json output or the run.json file under flow_cache.plan.
    • Normal execution: Successful tasks are written back to the specified store. The results are recorded in the run record as flow_cache.writeback.
    actrun <command> --flow-cache-store <path> --flow-signature <job-or-task>=<fingerprint>
  11. How WASM actions work in actrun

    main

    WASM actions are implemented as WASI-compatible WebAssembly modules. To use them, you must follow a specific directory structure and reference them using a specialized URI scheme.

    1. Module Placement: The compiled .wasm file must be placed in the following directory structure: _build/actrun/wasm_actions/<name>/<version>/main.wasm

    2. Workflow Reference: In your workflow YAML file, reference the action using the wasm:// protocol: - uses: wasm://<name>@<version>

    - uses: wasm://hello@v1
  12. Choose between `--worktree` and `--local` execution modes

    main

    When running workflows, you can control how files are accessed:

    • --worktree (Default): Creates a temporary git worktree to run the workflow in an isolated environment. This prevents the workflow from modifying or deleting files in your actual working directory.
    • --local: Runs the workflow directly in the current directory. Use this if you explicitly want the workflow to interact with your local files, but be aware it can modify your workspace.
    # Run in an isolated git worktree (safe default)
    actrun ci.yml
    
    # Run directly in the current directory
    actrun ci.yml --local