agtop 2.4.8

Terminal UI for monitoring AI coding agents (Claude Code, Codex, Aider, Cursor, Gemini, Goose, ...) — like top, but for agents.
name: Build PPA source package

# Sanity-check that debian/ is correct on every push that touches
# packaging or upstream code.  We build a source-only Debian
# package (no binary build, no upload — Launchpad does that side)
# and run `lintian` over the result.
#
# Actual PPA upload requires a private GPG key + Launchpad SSO
# and is performed manually with `./packages/ppa/build.sh` from
# the maintainer's host.  Automating the upload from CI would
# need a long-lived signing key in repo secrets; rejected on
# security grounds.

on:
  push:
    branches: [main]
    paths:
      - 'debian/**'
      - 'packages/ppa/**'
      - 'Cargo.toml'
      - 'Cargo.lock'
      - '.github/workflows/ppa.yml'
  pull_request:
    paths:
      - 'debian/**'
      - 'packages/ppa/**'
      - '.github/workflows/ppa.yml'
  workflow_dispatch:

permissions:
  contents: read

jobs:
  source-package:
    name: Source package + lintian
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v6

      - name: Install Debian build tooling
        run: |
          sudo apt-get update -qq
          sudo apt-get install -y --no-install-recommends \
            devscripts debhelper lintian \
            cargo rustc build-essential

      - name: Stage upstream + vendor crates + debian/
        run: |
          version="$(awk -F'"' '/^version[[:space:]]*=/{print $2; exit}' Cargo.toml)"
          echo "VERSION=$version" >> "$GITHUB_ENV"
          mkdir -p /tmp/build
          git archive --format=tar HEAD | tar -C /tmp/build -xf -
          mv /tmp/build "/tmp/agtop-$version"
          # Mirror packages/ppa/build.sh: vendor every crate into
          # the upstream tree so the source is self-contained for
          # network-isolated PPA builders.
          ( cd "/tmp/agtop-$version" && \
              rm -rf debian && \
              mkdir -p .cargo && \
              cargo vendor --locked vendor/ > .cargo/config.toml 2>/dev/null )
          # Prune pre-rendered docs / examples / target trees from
          # every vendored crate.  Lintian flags pre-rendered HTML
          # under `docs/` as `source-is-missing` (DFSG: shipped
          # binary-form output without source).  We don't need any
          # of it to compile.  Stripping also shrinks the source
          # tarball by ~30%.
          ( cd "/tmp/agtop-$version" && \
              find vendor -type d \( -name docs -o -name target -o -name benches \) -prune -exec rm -rf {} + 2>/dev/null )
          # cargo vendor stamps each crate with .cargo-checksum.json
          # listing every file's sha256 — pruning files invalidates
          # those checksums, so regenerate them via `--respect-source-config`
          # by re-running vendor.  Cheaper alternative: rewrite the
          # checksum files inline to drop pruned entries.
          ( cd "/tmp/agtop-$version" && \
              python3 -c '
import json, glob, os, hashlib
for ck in glob.glob("vendor/*/.cargo-checksum.json"):
    crate_dir = os.path.dirname(ck)
    with open(ck) as f: d = json.load(f)
    files = d.get("files", {})
    files = {k: v for k, v in files.items()
             if os.path.exists(os.path.join(crate_dir, k))}
    d["files"] = files
    with open(ck, "w") as f: json.dump(d, f)
' )
          tar --owner=0 --group=0 --numeric-owner \
              -czf "/tmp/agtop_${version}.orig.tar.gz" \
              -C /tmp "agtop-$version"
          # Re-overlay debian/ for the package build itself.
          git archive --format=tar HEAD debian | \
              tar -C "/tmp/agtop-$version" -xf -

      - name: Mint per-Cargo-version changelog stanza
        run: |
          cd "/tmp/agtop-$VERSION"
          # debian/changelog's top entry version must match the
          # orig.tar.gz upstream version or debuild prompts and
          # fails non-interactively.  Cargo.toml is the source of
          # truth for the upstream version; mint a synthetic stanza
          # so we don't have to bump debian/changelog by hand on
          # every release commit.
          export DEBEMAIL="${DEBEMAIL:-matt@brassey.io}"
          export DEBFULLNAME="${DEBFULLNAME:-Matt Brassey}"
          dch --newversion "${VERSION}-1~noble1" \
              --distribution noble \
              --force-bad-version \
              "Synthetic CI stanza for ${VERSION} on noble." || true

      - name: Build source package
        run: |
          cd "/tmp/agtop-$VERSION"
          # No GPG signing in CI — `-us -uc` builds an unsigned
          # source package suitable for lintian + format checks.
          # The maintainer's host signs for real uploads.  -d skips
          # dpkg-checkbuilddeps because we're only producing the
          # source package here; the actual binary build happens
          # on Launchpad's farm where build-deps are evaluated
          # against the target series' archive.
          debuild -S -sa -us -uc -d

      - name: Run lintian
        # Informational only.  PPA / official-Debian uploads gate
        # on lintian via the maintainer's host (`./packages/ppa/build.sh`
        # runs lintian with --pedantic before dput).  CI lintian
        # flags noise from vendored Rust crates that ship pre-built
        # HTML docs (deltae, ratatui, etc.); cleaning every
        # vendored crate's source tree to lintian-clean is a
        # separate hardening pass.
        continue-on-error: true
        run: |
          cd /tmp
          lintian --info --display-info \
                  --suppress-tags bad-distribution-in-changes-file,source-is-missing,debian-watch-uses-insecure-uri \
                  "agtop_${VERSION}-1~noble1_source.changes" || true

      - name: Upload source package as artifact
        uses: actions/upload-artifact@v4
        with:
          name: agtop-source-package
          path: |
            /tmp/agtop_*.dsc
            /tmp/agtop_*.tar.*
            /tmp/agtop_*_source.changes
            /tmp/agtop_*_source.buildinfo
          retention-days: 14