update ci
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
GITEA_SERVER_URL=
|
||||||
|
GITEA_REPOSITORY=
|
||||||
|
GITEA_TOKEN=
|
||||||
|
GITEA_REF_NAME=
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
out/
|
||||||
|
.env
|
||||||
@@ -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
|
||||||
Executable
+24
@@ -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"
|
||||||
@@ -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:
|
||||||
Executable
+48
@@ -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
@@ -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
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user