update ci

This commit is contained in:
2026-08-15 02:14:26 +05:00
parent aeb59e8eda
commit 226b1e1b42
8 changed files with 163 additions and 84 deletions
+4
View File
@@ -0,0 +1,4 @@
GITEA_SERVER_URL=
GITEA_REPOSITORY=
GITEA_TOKEN=
GITEA_REF_NAME=
+2
View File
@@ -0,0 +1,2 @@
out/
.env
+21
View File
@@ -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
+24
View File
@@ -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"
+22
View File
@@ -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:
+48
View File
@@ -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."
+13 -76
View File
@@ -1,32 +1,15 @@
name: Build self-hosted HTTP Toolkit name: Build & Release binary
on: on:
push: push:
branches: [main] tags:
tags: ['v*'] - 'v*'
pull_request:
workflow_dispatch: workflow_dispatch:
permissions:
contents: write # needed to publish releases on tags
jobs: jobs:
build: build:
strategy: runs-on: docker-compose
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: ${{ matrix.os }}
steps: steps:
- name: Checkout (with submodules) - name: Checkout (with submodules)
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -34,60 +17,14 @@ jobs:
submodules: recursive submodules: recursive
fetch-depth: 0 fetch-depth: 0
- name: Setup Node - name: Build Linux binary (docker)
uses: actions/setup-node@v4 working-directory: .build/prod
with: run: docker compose run --rm prod
node-version: 22
- name: Setup Bun - name: Create Gitea release & upload assets
uses: oven-sh/setup-bun@v2 if: startsWith(gitea.ref, 'refs/tags/')
with:
bun-version: latest
- name: Build
shell: bash
env: env:
OUT_NAME: httptoolkit GITEA_SERVER_URL: ${{ gitea.server_url }}
run: bash scripts/build.sh GITEA_REPOSITORY: ${{ gitea.repository }}
GITEA_TOKEN: ${{ secrets.PAT_GITEA }}
- name: Smoke test (unix) run: bash .build/prod/release.sh "${{ gitea.ref_name }}"
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
+29 -8
View File
@@ -30,7 +30,12 @@ updating to a new upstream release is a controlled, reviewable step.
│ ├── apply.sh # reset submodules → apply patches → copy overlay │ ├── apply.sh # reset submodules → apply patches → copy overlay
│ ├── build.sh # build UI → embed → bun compile → dist/ │ ├── build.sh # build UI → embed → bun compile → dist/
│ └── smoke.sh # launch binary & verify it serves + backend is up │ └── 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 ## 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 - **Single file via Bun `--compile`.** The server pulls in native `.node` addons
(`node-datachannel`, `registry-js`, `adbkit`, …). These **cannot be cross-compiled**, (`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` so the binary is built **per host platform**. `scripts/smoke.sh` is the guard: if a
step is the guard: if a native addon won't load from the embedded FS, it fails there. 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-<version>` - The UI is embedded as `ui.tar.gz` and extracted to `$TMPDIR/httptoolkit-ui-<version>`
on first run. on first run.
- No `HTK_SERVER_TOKEN` is set, so the local UI talks to the backend without a token. - 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 Matches the `docker-compose` runner convention:
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 - **`.gitea/workflows/build.yml`** — on a `v*` tag (or manual dispatch): checks out with
`.gitlab-ci.yml` (same steps: checkout w/ submodules → `scripts/build.sh``scripts/smoke.sh`). 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
```