kinjo 0.3.8

Kinjo: mDNS TUI and commands launch for local network services
Documentation
name: Check and Build Rust project

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]
  workflow_call:
    inputs:
      caller-run-id:
        description: >
          Run ID of the calling workflow. `github.event_name` cannot be used to
          detect a called run: inside a called workflow the github context is the
          caller's, so it is never 'workflow_call'.
        required: false
        type: string
        default: ""
      ref:
        description: >
          Exact commit to check out. Empty (the normal push/PR case) uses the
          triggering ref; a release caller pins its resolved release commit.
        required: false
        type: string
        default: ""

permissions:
  contents: read

# Cancel superseded runs when a branch is pushed again. A called run keys on the
# caller's run instead, so a push to main cannot cancel a release's gate.
concurrency:
  group: ci-test-${{ inputs.caller-run-id || github.ref }}
  cancel-in-progress: ${{ !inputs.caller-run-id }}

env:
  CARGO_TERM_COLOR: always

jobs:
  format:
    runs-on: ubuntu-24.04
    timeout-minutes: 10
    steps:
    - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
      with:
        ref: ${{ inputs.ref }}
        persist-credentials: false
    - name: Check formatting
      run: cargo fmt -- --check

  clippy:
    name: Clippy on ${{ matrix.os }}
    runs-on: ${{ matrix.os }}

    strategy:
      fail-fast: false
      matrix:
        # Lint on every target OS so cfg-gated code paths (e.g. the
        # windows/unix branches in plumber::exec) are not lint-blind.
        os: [ubuntu-24.04, windows-2025, macos-15]

    timeout-minutes: 30

    steps:
    - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
      with:
        ref: ${{ inputs.ref }}
        persist-credentials: false
    - name: Set up build environment
      uses: ./.github/actions/setup
      with:
        install-avahi: ${{ matrix.os == 'ubuntu-24.04' }}
    - name: Run clippy
      run: cargo clippy --locked --all-targets -- -D warnings
    # The zeroconf backend is feature-gated and needs the Avahi client
    # headers, which only the Linux runner installs.
    - name: Run clippy (all features)
      if: matrix.os == 'ubuntu-24.04'
      run: cargo clippy --locked --all-targets --all-features -- -D warnings

  build:
    name: Build on ${{ matrix.os }}
    runs-on: ${{ matrix.os }}

    strategy:
      fail-fast: false
      matrix:
        # Defines the target operating systems
        os: [ubuntu-24.04, windows-2025, macos-15]

    timeout-minutes: 30

    steps:
    - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
      with:
        ref: ${{ inputs.ref }}
        persist-credentials: false

    - name: Set up build environment
      uses: ./.github/actions/setup
      with:
        install-avahi: ${{ matrix.os == 'ubuntu-24.04' }}

    # `cargo test` builds every target it needs, so a separate build step
    # would only duplicate work.
    - name: Run tests
      run: cargo test --locked

    # The zeroconf backend is feature-gated and needs the Avahi client
    # headers, which only the Linux runner installs.
    - name: Run tests (all features)
      if: matrix.os == 'ubuntu-24.04'
      run: cargo test --locked --all-features

  tui-smoke:
    name: Smoke-test the rendered TUI
    runs-on: ubuntu-24.04
    timeout-minutes: 10

    env:
      KINJO_TIMEOUT: "15"
      # ubuntu-24.04 ships tmux 3.4, which intermittently signals the pane
      # process during teardown and surfaces here as a spurious "crash on quit".
      # tmux >= 3.5 is clean, so build 3.5a from source instead of the distro
      # package. See docs/tui-smoke-crash-handover.md.
      TMUX_VERSION: "3.5a"

    steps:
    - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
      with:
        ref: ${{ inputs.ref }}
        persist-credentials: false
    - name: Set up build environment
      uses: ./.github/actions/setup
    - name: Cache tmux ${{ env.TMUX_VERSION }}
      id: tmux-cache
      uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
      with:
        path: /usr/local/bin/tmux
        key: tmux-${{ runner.os }}-${{ env.TMUX_VERSION }}
    - name: Install tmux runtime library
      # libevent's runtime lib is pulled in by libevent-dev when building, but is
      # absent on a cache hit (build skipped), so install it unconditionally.
      run: |
        sudo apt-get update
        sudo apt-get install -y libevent-2.1-7
    - name: Build tmux ${{ env.TMUX_VERSION }} from source
      if: steps.tmux-cache.outputs.cache-hit != 'true'
      run: |
        sudo apt-get install -y build-essential libevent-dev libncurses-dev bison pkg-config
        curl --proto '=https' -fsSLo tmux.tar.gz \
          "https://github.com/tmux/tmux/releases/download/${TMUX_VERSION}/tmux-${TMUX_VERSION}.tar.gz"
        tar xzf tmux.tar.gz
        (cd "tmux-${TMUX_VERSION}" && ./configure && make -j"$(nproc)" && sudo make install)
    - name: Verify tmux version
      run: |
        hash -r
        echo "using $(command -v tmux): $(tmux -V)"
    - name: Smoke-test the default terminal size
      run: scripts/smoke-tui.sh
    - name: Smoke-test a short, narrow terminal
      env:
        KINJO_COLS: "60"
        KINJO_ROWS: "18"
      run: scripts/smoke-tui.sh