Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99ae2a5fd7 | ||
|
|
9da6118a35 | ||
|
|
efd82c6284 | ||
|
|
e9cf5e8739 | ||
|
|
ff4e2a5c5d | ||
|
|
2ef9f80fc1 | ||
|
|
6fe549e34e | ||
|
|
406a8f86b1 |
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "trx-rs SDK",
|
||||
"image": "git.haxx.space/sjg/trx-rs/sdk:latest",
|
||||
"workspaceFolder": "/work",
|
||||
"workspaceMount": "source=${localWorkspaceFolder},target=/work,type=bind",
|
||||
"mounts": [
|
||||
"source=trx-rs-sccache,target=/sccache,type=volume"
|
||||
],
|
||||
"containerEnv": {
|
||||
"RUSTC_WRAPPER": "sccache",
|
||||
"CARGO_INCREMENTAL": "0",
|
||||
"SCCACHE_DIR": "/sccache"
|
||||
},
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"rust-lang.rust-analyzer",
|
||||
"tamasfe.even-better-toml"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
-73
@@ -2,6 +2,11 @@
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
# CI for the Docker-executor runner (VM). The lint/test jobs run inside the
|
||||
# shared trx-rs SDK image (container/Containerfile), which bakes in the pinned
|
||||
# Rust toolchain and all build dependencies. The reuse job uses the upstream
|
||||
# Docker action, which the Docker executor launches as a sibling container.
|
||||
|
||||
name: CI
|
||||
|
||||
on:
|
||||
@@ -11,96 +16,43 @@ on:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
# sccache: shared compilation cache persisted on the runner host (see the
|
||||
# -v mount in runner-config.example.yaml). CARGO_INCREMENTAL=0 because
|
||||
# sccache cannot cache incremental artifacts.
|
||||
RUSTC_WRAPPER: sccache
|
||||
CARGO_INCREMENTAL: "0"
|
||||
SCCACHE_DIR: /sccache
|
||||
SCCACHE_CACHE_SIZE: "20G"
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
container: git.haxx.space/sjg/trx-rs/sdk:latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install system dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential pkg-config cmake clang libclang-dev \
|
||||
libopus-dev libasound2-dev libsoapysdr-dev
|
||||
|
||||
- name: Set up Rust
|
||||
run: |
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
if ! command -v rustup >/dev/null 2>&1; then
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
|
||||
| sh -s -- -y --profile minimal
|
||||
fi
|
||||
rustup toolchain install stable --profile minimal \
|
||||
--component rustfmt --component clippy
|
||||
rustup default stable
|
||||
|
||||
- name: Cache cargo
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: cargo-${{ runner.os }}-
|
||||
|
||||
- name: rustfmt
|
||||
run: |
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
cargo fmt --all -- --check
|
||||
|
||||
run: cargo fmt --all -- --check
|
||||
- name: clippy
|
||||
run: |
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||
run: cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||
- name: sccache stats
|
||||
if: always()
|
||||
run: sccache --show-stats
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
container: git.haxx.space/sjg/trx-rs/sdk:latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install system dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
build-essential pkg-config cmake clang libclang-dev \
|
||||
libopus-dev libasound2-dev libsoapysdr-dev
|
||||
|
||||
- name: Set up Rust
|
||||
run: |
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
if ! command -v rustup >/dev/null 2>&1; then
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
|
||||
| sh -s -- -y --profile minimal
|
||||
fi
|
||||
rustup toolchain install stable --profile minimal
|
||||
rustup default stable
|
||||
|
||||
- name: Cache cargo
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: cargo-${{ runner.os }}-
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
cargo build --workspace --all-targets --locked
|
||||
|
||||
run: cargo build --workspace --all-targets --locked
|
||||
- name: Test
|
||||
run: |
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
cargo test --workspace --locked
|
||||
run: cargo test --workspace --locked
|
||||
- name: sccache stats
|
||||
if: always()
|
||||
run: sccache --show-stats
|
||||
|
||||
reuse:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: REUSE compliance
|
||||
uses: fsfe/reuse-action@v5
|
||||
- uses: fsfe/reuse-action@v5
|
||||
|
||||
@@ -12,6 +12,8 @@ path = [
|
||||
"trx-rs.toml.example",
|
||||
"docs/**",
|
||||
"aidocs/**",
|
||||
"container/**",
|
||||
".devcontainer/**",
|
||||
"src/decoders/trx-ftx/README.md",
|
||||
"src/decoders/trx-wxsat/README.md",
|
||||
"assets/trx-logo.png",
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# SPDX-FileCopyrightText: 2026 Stan Grams <sjg@haxx.space>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
# trx-rs SDK / build image.
|
||||
#
|
||||
# Single source of truth for the build environment. Used two ways:
|
||||
# * CI — as the job container for the lint/test jobs (Docker executor).
|
||||
# * Dev — run locally or via .devcontainer for a reproducible toolchain.
|
||||
#
|
||||
# Pinning the Rust version here (and in rust-toolchain.toml) means CI and every
|
||||
# developer share the exact same rustc/clippy, so "works locally, fails in CI"
|
||||
# cannot happen.
|
||||
FROM docker.io/library/debian:bookworm-slim
|
||||
|
||||
# Keep in sync with rust-toolchain.toml.
|
||||
ARG RUST_VERSION=1.97.1
|
||||
ARG NODE_MAJOR=20
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive \
|
||||
RUSTUP_HOME=/usr/local/rustup \
|
||||
CARGO_HOME=/usr/local/cargo \
|
||||
PATH=/usr/local/cargo/bin:/usr/local/bin:/usr/bin:/bin
|
||||
|
||||
# Build dependencies (mirror README's manual instructions).
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates curl git \
|
||||
build-essential pkg-config cmake clang libclang-dev \
|
||||
libopus-dev libasound2-dev libsoapysdr-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Node.js — JS-based actions (actions/checkout, actions/cache) run *inside*
|
||||
# the job container under the Docker executor, so node must be present.
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_MAJOR}.x | bash - \
|
||||
&& apt-get install -y --no-install-recommends nodejs \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Pinned Rust toolchain, installed world-readable so any UID the runner or a
|
||||
# devcontainer uses can invoke cargo.
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
|
||||
| sh -s -- -y --no-modify-path \
|
||||
--default-toolchain "${RUST_VERSION}" --profile minimal \
|
||||
--component rustfmt --component clippy \
|
||||
&& chmod -R a+rwX "$RUSTUP_HOME" "$CARGO_HOME"
|
||||
|
||||
# sccache — shared compilation cache. Enabled at build time via
|
||||
# RUSTC_WRAPPER (see the CI workflow and .devcontainer), not repo-wide, so
|
||||
# non-SDK builds are unaffected. musl build is static and runs anywhere.
|
||||
ARG SCCACHE_VERSION=0.8.2
|
||||
RUN curl -fsSL "https://github.com/mozilla/sccache/releases/download/v${SCCACHE_VERSION}/sccache-v${SCCACHE_VERSION}-x86_64-unknown-linux-musl.tar.gz" \
|
||||
| tar -xz -C /tmp \
|
||||
&& install -m755 "/tmp/sccache-v${SCCACHE_VERSION}-x86_64-unknown-linux-musl/sccache" /usr/local/bin/sccache \
|
||||
&& rm -rf /tmp/sccache-*
|
||||
|
||||
WORKDIR /work
|
||||
@@ -0,0 +1,130 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2026 Stan Grams <sjg@haxx.space>
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
-->
|
||||
|
||||
# trx-rs SDK image
|
||||
|
||||
A single container image that is the canonical build environment for trx-rs,
|
||||
used **both** by CI and by developers. It bakes in the pinned Rust toolchain
|
||||
(matching `rust-toolchain.toml`) and every build dependency, so the compiler
|
||||
and `clippy` are identical everywhere — no "works on my machine".
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `Containerfile` | The SDK image (Debian + build deps + pinned Rust + Node + git). |
|
||||
| `runner-config.example.yaml` | Example act_runner config for the CI VM (Docker executor). |
|
||||
|
||||
## Build and publish
|
||||
|
||||
```bash
|
||||
# from the repo root
|
||||
podman build -t git.haxx.space/sjg/trx-rs/sdk:latest container
|
||||
podman login git.haxx.space
|
||||
podman push git.haxx.space/sjg/trx-rs/sdk:latest
|
||||
```
|
||||
|
||||
Tag with the Rust version too (e.g. `:1.97.1`) if you want reproducible pins.
|
||||
Make the package **public** (Gitea → Packages → the image → Settings) so the CI
|
||||
runner and developers can pull it without credentials. If you keep it private,
|
||||
add `credentials:` under the workflow's `container:` and log the runner into the
|
||||
registry.
|
||||
|
||||
## Developer use
|
||||
|
||||
Reproducible one-off build, no local toolchain needed:
|
||||
|
||||
```bash
|
||||
podman run --rm -it -v "$PWD":/work -w /work \
|
||||
git.haxx.space/sjg/trx-rs/sdk:latest \
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
Or open the repo in the image via VS Code / JetBrains "Reopen in Container"
|
||||
(`.devcontainer/devcontainer.json` points at the same image).
|
||||
|
||||
Building outside the container? `rust-toolchain.toml` pins the same rustc, so
|
||||
`rustup` installs the matching toolchain automatically.
|
||||
|
||||
## CI use
|
||||
|
||||
`.gitea/workflows/ci.yml` runs the `lint` and `test` jobs *inside* this image
|
||||
via the `container:` key, so they skip all setup and go straight to `cargo`.
|
||||
The `reuse` job stays on the upstream `fsfe/reuse-action` (a Docker action the
|
||||
Docker executor launches as a sibling container) — nothing REUSE-related is
|
||||
baked into the SDK.
|
||||
|
||||
## Compilation cache (sccache)
|
||||
|
||||
The SDK image ships [`sccache`](https://github.com/mozilla/sccache). It is
|
||||
enabled via `RUSTC_WRAPPER=sccache` in CI and the devcontainer (not repo-wide,
|
||||
so plain `cargo` builds outside the SDK are unaffected).
|
||||
|
||||
- **CI** persists the cache on the runner host — create the dir once:
|
||||
`mkdir -p /var/cache/sccache`. It is bind-mounted into each job container at
|
||||
`/sccache` (see `runner-config.example.yaml`), so cache survives across runs
|
||||
and is shared between the lint/test jobs and both projects.
|
||||
- **Devcontainer** uses a named volume (`trx-rs-sccache`).
|
||||
- Check effectiveness with `sccache --show-stats` (the CI jobs print it).
|
||||
|
||||
`CARGO_INCREMENTAL=0` is set wherever sccache is on, since sccache cannot cache
|
||||
incremental artifacts.
|
||||
|
||||
## CI runner (Alpine / OpenRC)
|
||||
|
||||
The runner uses the **Docker executor** (not the host executor): per-job
|
||||
container isolation and standard `ubuntu-latest` semantics. `act_runner` runs
|
||||
as an OpenRC service. Files provided:
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `act_runner.openrc` | OpenRC init script (`supervise-daemon`, depends on docker). |
|
||||
| `act_runner.confd.example` | Per-instance `conf.d` settings for multi-runner hosts. |
|
||||
|
||||
**Cap the thread budget.** In a VM, pin its vCPUs to specific host threads
|
||||
(libvirt/KVM):
|
||||
|
||||
```xml
|
||||
<vcpu placement='static'>2</vcpu>
|
||||
<cputune>
|
||||
<vcpupin vcpu='0' cpuset='4'/>
|
||||
<vcpupin vcpu='1' cpuset='5'/>
|
||||
</cputune>
|
||||
```
|
||||
|
||||
On bare metal, the `container.options: "--cpus=2"` and `capacity: 1` in
|
||||
`runner-config.example.yaml` already bound each runner.
|
||||
|
||||
**Set it up:**
|
||||
|
||||
```bash
|
||||
# 1. Docker + a dedicated user with socket access
|
||||
apk add docker docker-cli
|
||||
rc-update add docker default && rc-service docker start
|
||||
adduser -S -D -H -h /var/lib/act_runner act
|
||||
addgroup act docker
|
||||
|
||||
# 2. act_runner binary (static Go build, works on musl)
|
||||
curl -fsSL -o /usr/local/bin/act_runner \
|
||||
https://gitea.com/gitea/act_runner/releases/download/v0.2.11/act_runner-0.2.11-linux-amd64
|
||||
chmod +x /usr/local/bin/act_runner
|
||||
|
||||
# 3. Config + register one runner per project (scope keeps their jobs apart)
|
||||
install -Dm644 container/runner-config.example.yaml /etc/act_runner/trx-rs.yaml
|
||||
install -d -o act /var/lib/act_runner/trx-rs
|
||||
su act -s /bin/sh -c 'cd /var/lib/act_runner/trx-rs && \
|
||||
act_runner register --no-interactive \
|
||||
--instance https://git.haxx.space --token <TOKEN> \
|
||||
--name trx-rs-ci \
|
||||
--labels "ubuntu-latest:docker://catthehacker/ubuntu:act-latest"'
|
||||
|
||||
# 4. OpenRC service (repeat the symlink+conf.d for the second project)
|
||||
install -m755 container/act_runner.openrc /etc/init.d/act_runner
|
||||
ln -s act_runner /etc/init.d/act_runner.trx-rs
|
||||
install -m644 container/act_runner.confd.example /etc/conf.d/act_runner.trx-rs
|
||||
rc-update add act_runner.trx-rs default
|
||||
rc-service act_runner.trx-rs start
|
||||
```
|
||||
|
||||
Check it with `rc-service act_runner.trx-rs status` and
|
||||
`tail -f /var/log/act_runner.trx-rs.log`.
|
||||
@@ -0,0 +1,14 @@
|
||||
# SPDX-FileCopyrightText: 2026 Stan Grams <sjg@haxx.space>
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Per-instance settings for an act_runner OpenRC service.
|
||||
# Copy to /etc/conf.d/<service-name>, e.g. /etc/conf.d/act_runner.trx-rs
|
||||
# (the name must match the /etc/init.d/ symlink).
|
||||
|
||||
# User that runs the daemon. Must be a member of the `docker` group.
|
||||
runner_user="act"
|
||||
|
||||
# Per-instance state dir (holds the .runner registration) and config file,
|
||||
# so two runners on one host stay independent.
|
||||
runner_dir="/var/lib/act_runner/trx-rs"
|
||||
runner_config="/etc/act_runner/trx-rs.yaml"
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/sbin/openrc-run
|
||||
# SPDX-FileCopyrightText: 2026 Stan Grams <sjg@haxx.space>
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# OpenRC service for a Gitea act_runner (Docker executor) on Alpine.
|
||||
#
|
||||
# Install as /etc/init.d/act_runner (chmod +x). Single instance uses
|
||||
# /etc/act_runner/config.yaml. For one runner per project, symlink this script
|
||||
# and add a matching conf.d file:
|
||||
#
|
||||
# ln -s act_runner /etc/init.d/act_runner.trx-rs
|
||||
# cp container/act_runner.confd.example /etc/conf.d/act_runner.trx-rs
|
||||
# $EDITOR /etc/conf.d/act_runner.trx-rs # set runner_dir / runner_config
|
||||
# rc-update add act_runner.trx-rs default
|
||||
# rc-service act_runner.trx-rs start
|
||||
|
||||
description="Gitea Actions runner"
|
||||
|
||||
: "${runner_user:=act}"
|
||||
: "${runner_dir:=/var/lib/act_runner}"
|
||||
: "${runner_config:=/etc/act_runner/config.yaml}"
|
||||
|
||||
command="/usr/local/bin/act_runner"
|
||||
command_args="daemon --config ${runner_config}"
|
||||
# No group given, so supplementary groups (incl. docker) are initialised.
|
||||
command_user="${runner_user}"
|
||||
directory="${runner_dir}"
|
||||
|
||||
supervisor="supervise-daemon"
|
||||
respawn_delay=5
|
||||
respawn_max=0
|
||||
pidfile="/run/${RC_SVCNAME}.pid"
|
||||
output_log="/var/log/${RC_SVCNAME}.log"
|
||||
error_log="/var/log/${RC_SVCNAME}.log"
|
||||
|
||||
depend() {
|
||||
need docker
|
||||
use net dns
|
||||
}
|
||||
|
||||
start_pre() {
|
||||
checkpath -d -m 0750 -o "${runner_user}" "${runner_dir}"
|
||||
checkpath -f -m 0640 -o "${runner_user}" "${output_log}"
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
# SPDX-FileCopyrightText: 2026 Stan Grams <sjg@haxx.space>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Example act_runner config for the Docker-executor runner that lives in the
|
||||
# CI VM. This is NOT the SDK image — it configures the runner that launches
|
||||
# per-job containers (including the trx-rs SDK image referenced by the
|
||||
# workflow's `container:` key). Copy to the VM and pass with
|
||||
# `act_runner daemon --config`.
|
||||
|
||||
log:
|
||||
level: info
|
||||
|
||||
runner:
|
||||
file: .runner
|
||||
# One concurrent job. With one runner per project on a 2-vCPU VM this keeps
|
||||
# total CI usage at ~2 threads.
|
||||
capacity: 1
|
||||
timeout: 3h
|
||||
# Docker executor: no ":host" suffix. Maps runs-on labels to base images
|
||||
# (the workflow overrides these per job via `container:`).
|
||||
labels:
|
||||
- "ubuntu-latest:docker://catthehacker/ubuntu:act-latest"
|
||||
|
||||
cache:
|
||||
enabled: true
|
||||
|
||||
container:
|
||||
# Cap every job container's CPU so CI stays within the 2-thread budget even
|
||||
# if capacity is raised later. The -v mount persists the sccache cache on the
|
||||
# host (create it first: `mkdir -p /var/cache/sccache`), matching SCCACHE_DIR
|
||||
# in the workflow.
|
||||
options: "--cpus=2 -v /var/cache/sccache:/sccache"
|
||||
# Reuse the host VM's Docker network for the built-in cache/artifact server.
|
||||
network: "host"
|
||||
@@ -0,0 +1,11 @@
|
||||
# SPDX-FileCopyrightText: 2026 Stan Grams <sjg@haxx.space>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Pins the Rust toolchain for reproducible builds. Keep in sync with the
|
||||
# SDK image (container/Containerfile, ARG RUST_VERSION). rustup honours this
|
||||
# automatically for local builds outside the SDK container.
|
||||
|
||||
[toolchain]
|
||||
channel = "1.97.1"
|
||||
components = ["rustfmt", "clippy"]
|
||||
Reference in New Issue
Block a user