From 226b1e1b427bd33a2ff744d2cdead2da774e74af Mon Sep 17 00:00:00 2001 From: Shihaam Abdul Rahman Date: Sat, 15 Aug 2026 02:14:26 +0500 Subject: [PATCH] update ci --- .build/prod/.env.example | 4 ++ .build/prod/.gitignore | 2 + .build/prod/Dockerfile | 21 +++++++++ .build/prod/build.sh | 24 ++++++++++ .build/prod/compose.yml | 22 ++++++++++ .build/prod/release.sh | 48 ++++++++++++++++++++ .gitea/workflows/build.yml | 89 ++++++-------------------------------- README.md | 37 ++++++++++++---- 8 files changed, 163 insertions(+), 84 deletions(-) create mode 100644 .build/prod/.env.example create mode 100644 .build/prod/.gitignore create mode 100644 .build/prod/Dockerfile create mode 100755 .build/prod/build.sh create mode 100644 .build/prod/compose.yml create mode 100755 .build/prod/release.sh diff --git a/.build/prod/.env.example b/.build/prod/.env.example new file mode 100644 index 0000000..967b4a6 --- /dev/null +++ b/.build/prod/.env.example @@ -0,0 +1,4 @@ +GITEA_SERVER_URL= +GITEA_REPOSITORY= +GITEA_TOKEN= +GITEA_REF_NAME= diff --git a/.build/prod/.gitignore b/.build/prod/.gitignore new file mode 100644 index 0000000..ccf91ba --- /dev/null +++ b/.build/prod/.gitignore @@ -0,0 +1,2 @@ +out/ +.env diff --git a/.build/prod/Dockerfile b/.build/prod/Dockerfile new file mode 100644 index 0000000..e6f74c5 --- /dev/null +++ b/.build/prod/Dockerfile @@ -0,0 +1,21 @@ +# Builder image for the self-hosted HTTP Toolkit single-file binary (Linux x64). +# Provides Node, Bun, and the toolchain needed to build the server's native modules. +FROM node:22-bookworm + +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + python3 \ + cmake \ + pkg-config \ + git \ + curl \ + unzip \ + ca-certificates \ + jq \ + && rm -rf /var/lib/apt/lists/* + +# Install Bun (used for the single-file `--compile` step) +RUN curl -fsSL https://bun.sh/install | bash +ENV PATH="/root/.bun/bin:${PATH}" + +WORKDIR /source diff --git a/.build/prod/build.sh b/.build/prod/build.sh new file mode 100755 index 0000000..12da8a6 --- /dev/null +++ b/.build/prod/build.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# +# Runs INSIDE the .build/prod container. Builds the Linux single-file binary and +# drops it into .build/prod/out/ (mounted back to the host for the release step). +# +set -euo pipefail +cd /source + +# The repo is bind-mounted from the host (owned by a different uid), so git +# refuses to operate on it until we mark it safe: +git config --global --add safe.directory '*' + +OUT_DIR="/source/.build/prod/out" +mkdir -p "$OUT_DIR" + +# Reuse the platform-agnostic build (apply patches → build UI → embed → bun compile): +OUT_NAME=httptoolkit bash scripts/build.sh + +# Smoke-test the Linux binary before we consider it releasable: +bash scripts/smoke.sh dist/httptoolkit + +cp -v dist/httptoolkit "$OUT_DIR/httptoolkit-linux-x64" +echo "==> Artifacts:" +ls -lh "$OUT_DIR" diff --git a/.build/prod/compose.yml b/.build/prod/compose.yml new file mode 100644 index 0000000..b72738f --- /dev/null +++ b/.build/prod/compose.yml @@ -0,0 +1,22 @@ +services: + prod: + build: + context: . + dockerfile: Dockerfile + image: htk-prod-builder:local + network_mode: host + working_dir: /source + environment: + - PUPPETEER_SKIP_DOWNLOAD=true + - PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true + volumes: + # The whole repo (with submodules already checked out by the CI step): + - ../../:/source + # Persist package caches between runs to speed up rebuilds: + - htk-npm-cache:/root/.npm + - htk-bun-cache:/root/.bun/install/cache + command: bash .build/prod/build.sh + +volumes: + htk-npm-cache: + htk-bun-cache: diff --git a/.build/prod/release.sh b/.build/prod/release.sh new file mode 100755 index 0000000..2e69c02 --- /dev/null +++ b/.build/prod/release.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# +# Create a Gitea release for a tag and upload everything in out/. +# Mirrors the repo's existing Gitea-API release convention. +# +# Config via env (or a local .env next to this script): +# GITEA_SERVER_URL, GITEA_REPOSITORY, GITEA_TOKEN +# Tag: passed as $1 (in CI: gitea.ref_name), else derived from the current commit. +# +set -euo pipefail +cd "$(dirname "$0")" + +# Optional: load credentials from a local .env for manual runs. +[ -f .env ] && source ./.env + +: "${GITEA_SERVER_URL:?}" +: "${GITEA_REPOSITORY:?}" +: "${GITEA_TOKEN:?}" + +TAG="${1:-$(git tag --points-at HEAD | head -n1)}" +[ -n "$TAG" ] || { echo "No tag (pass as arg, or run on a tagged commit)"; exit 1; } + +OUT_DIR="$(pwd)/out" +API="${GITEA_SERVER_URL}/api/v1/repos/${GITEA_REPOSITORY}/releases" + +echo "==> Creating release $TAG" +RESP=$(curl -s -X POST "$API" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + -H "Content-Type: application/json" \ + -d "{\"tag_name\": \"${TAG}\", \"name\": \"HTTP Toolkit ${TAG}\", \"body\": \"Self-hosted single-file build.\"}") + +RID=$(echo "$RESP" | jq -r '.id') +if [ "$RID" = "null" ] || [ -z "$RID" ]; then + echo "!! Failed to create release:"; echo "$RESP"; exit 1 +fi +echo "==> Release id $RID" + +shopt -s nullglob +for f in "$OUT_DIR"/*; do + [ -f "$f" ] || continue + name=$(basename "$f") + echo "==> Uploading $name" + curl -s -X POST "${API}/${RID}/assets?name=${name}" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + -H "Content-Type: application/octet-stream" \ + --data-binary "@${f}" > /dev/null +done +echo "==> Release complete." diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 0be9465..787eaae 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -1,32 +1,15 @@ -name: Build self-hosted HTTP Toolkit +name: Build & Release binary on: push: - branches: [main] - tags: ['v*'] - pull_request: + tags: + - 'v*' workflow_dispatch: -permissions: - contents: write # needed to publish releases on tags - jobs: build: - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu-latest - name: linux-x64 - smoke: true - - os: macos-latest # Apple Silicon runner (arm64) - name: macos-arm64 - smoke: true - - os: windows-latest - name: windows-x64 - smoke: false # background-process smoke is unix-only; --help still runs + runs-on: docker-compose - runs-on: ${{ matrix.os }} steps: - name: Checkout (with submodules) uses: actions/checkout@v4 @@ -34,60 +17,14 @@ jobs: submodules: recursive fetch-depth: 0 - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: 22 + - name: Build Linux binary (docker) + working-directory: .build/prod + run: docker compose run --rm prod - - name: Setup Bun - uses: oven-sh/setup-bun@v2 - with: - bun-version: latest - - - name: Build - shell: bash + - name: Create Gitea release & upload assets + if: startsWith(gitea.ref, 'refs/tags/') env: - OUT_NAME: httptoolkit - run: bash scripts/build.sh - - - name: Smoke test (unix) - if: matrix.smoke - shell: bash - run: bash scripts/smoke.sh dist/httptoolkit - - - name: Windows sanity (--help) - if: matrix.os == 'windows-latest' - shell: bash - run: ./dist/httptoolkit.exe --help - - - name: Stage artifact - shell: bash - run: | - mkdir -p out - if [ "${{ matrix.os }}" = "windows-latest" ]; then - cp dist/httptoolkit.exe "out/httptoolkit-${{ matrix.name }}.exe" - else - cp dist/httptoolkit "out/httptoolkit-${{ matrix.name }}" - fi - - - name: Upload build artifact - uses: actions/upload-artifact@v4 - with: - name: httptoolkit-${{ matrix.name }} - path: out/* - - release: - # Publish a GitHub release only when a v* tag is pushed. - if: startsWith(github.ref, 'refs/tags/v') - needs: build - runs-on: ubuntu-latest - steps: - - name: Download all artifacts - uses: actions/download-artifact@v4 - with: - path: artifacts - - name: Publish release - uses: softprops/action-gh-release@v2 - with: - files: artifacts/**/* - generate_release_notes: true + GITEA_SERVER_URL: ${{ gitea.server_url }} + GITEA_REPOSITORY: ${{ gitea.repository }} + GITEA_TOKEN: ${{ secrets.PAT_GITEA }} + run: bash .build/prod/release.sh "${{ gitea.ref_name }}" diff --git a/README.md b/README.md index dade4b6..e6a6aac 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,12 @@ updating to a new upstream release is a controlled, reviewable step. │ ├── apply.sh # reset submodules → apply patches → copy overlay │ ├── build.sh # build UI → embed → bun compile → dist/ │ └── smoke.sh # launch binary & verify it serves + backend is up -└── .github/workflows/build.yml +├── .build/prod/ # Docker builder (Gitea `docker-compose` runner) +│ ├── Dockerfile # Node + Bun + native toolchain +│ ├── compose.yml # mounts repo, runs build.sh +│ ├── build.sh # build + smoke → out/ +│ └── release.sh # Gitea-API release + upload +└── .gitea/workflows/build.yml ``` ## What the patches change @@ -93,15 +98,31 @@ ever need attention on upgrade. - **Single file via Bun `--compile`.** The server pulls in native `.node` addons (`node-datachannel`, `registry-js`, `adbkit`, …). These **cannot be cross-compiled**, - so CI builds each OS on its own runner (Linux/macOS/Windows matrix). The `smoke.sh` - step is the guard: if a native addon won't load from the embedded FS, it fails there. + so the binary is built **per host platform**. `scripts/smoke.sh` is the guard: if a + native addon won't load from the embedded FS, it fails there. +- **Linux only, for now.** CI builds inside a Linux Docker container, which produces a + trustworthy Linux x64 binary. Windows/macOS binaries are **not** reliably buildable + from Linux Docker (foreign-platform native addons can't be produced or smoke-tested + there, and macOS needs signing) — they'd need real Windows/macOS runners. - The UI is embedded as `ui.tar.gz` and extracted to `$TMPDIR/httptoolkit-ui-` on first run. - No `HTK_SERVER_TOKEN` is set, so the local UI talks to the backend without a token. -## CI +## CI (Gitea Actions, Docker) -`.github/workflows/build.yml` builds the matrix on push/PR and publishes a GitHub Release -on `v*` tags. **If your CI is Gitea/Forgejo Actions**, this same file works under -`.gitea/workflows/` or `.github/workflows/`. **If it's GitLab**, it needs porting to -`.gitlab-ci.yml` (same steps: checkout w/ submodules → `scripts/build.sh` → `scripts/smoke.sh`). +Matches the `docker-compose` runner convention: + +- **`.gitea/workflows/build.yml`** — on a `v*` tag (or manual dispatch): checks out with + submodules, runs `docker compose run --rm prod` in `.build/prod/`, then creates a Gitea + release and uploads the artifacts via the Gitea API (`secrets.PAT_GITEA`). +- **`.build/prod/`** — the Docker builder: + - `Dockerfile` — Node 22 + Bun + native-build toolchain + - `compose.yml` — mounts the repo at `/source`, caches npm/bun + - `build.sh` — runs `scripts/build.sh` + `scripts/smoke.sh`, drops the binary in `out/` + - `release.sh` — Gitea-API release + asset upload + +Tag a release: + +```bash +git tag v1.27.1 && git push origin v1.27.1 +```