Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 91 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,34 @@ name: CI

on:
push:
branches: [ main ]
branches: [ main, 'release/**' ]
pull_request:
branches: [ main ]
branches: [ main, 'release/**' ]
workflow_dispatch:
schedule:
- cron: '17 3 * * *'

permissions:
contents: read

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build-and-test:
pr-gate:
name: PR gate (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
os: [ubuntu-24.04, macos-latest]

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Install dependencies (Ubuntu)
if: runner.os == 'Linux'
Expand All @@ -42,11 +54,26 @@ jobs:
- name: Run release preflight
run: make release-check

extended-linux-runtime:
name: Extended Linux runtime
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || github.event_name == 'push'
runs-on: ubuntu-24.04

steps:
- uses: actions/checkout@v6

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y expect libssh-dev valgrind

- name: Run extended release preflight
run: |
RUN_INTEGRATION=1 RUN_SOAK=1 RUN_SLOW_CLIENT=1 make release-check

- name: Check for memory leaks
if: runner.os == 'Linux'
run: |
set -eu
sudo apt-get install -y valgrind
STATE_DIR=$(mktemp -d)
SERVER_LOG="$STATE_DIR/server.log"
VALGRIND_LOG="$STATE_DIR/valgrind.log"
Expand Down Expand Up @@ -101,3 +128,60 @@ jobs:
cat "$VALGRIND_LOG"
exit 1
fi

portable-container-builds:
name: Portable build (${{ matrix.name }})
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || github.event_name == 'push'
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
include:
- name: debian-stable-glibc
image: debian:stable-slim
setup: apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends build-essential libssh-dev ca-certificates
- name: ubuntu-24.04-glibc
image: ubuntu:24.04
setup: apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends build-essential libssh-dev ca-certificates
- name: alpine-musl
image: alpine:3.20
setup: apk add --no-cache build-base libssh-dev ca-certificates

steps:
- uses: actions/checkout@v6

- name: Build in container
run: |
docker run --rm -v "$PWD:/src:ro" "${{ matrix.image }}" sh -c '
set -eu
${{ matrix.setup }}
mkdir /work
cp -R /src/. /work/
cd /work
make clean
make
./tnt --version
./tntctl --version
'

package-recipe-gate:
name: Package recipe gate
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || github.event_name == 'push'
runs-on: ubuntu-24.04

steps:
- uses: actions/checkout@v6

- name: Install packaging tools
run: |
sudo apt-get update
sudo apt-get install -y ruby cpio

- name: Validate packaging metadata
run: |
for script in scripts/*.sh; do
sh -n "$script"
done
bash -n packaging/arch/PKGBUILD
ruby -c packaging/homebrew/tnt-chat.rb
scripts/package_debian_source.sh "$RUNNER_TEMP/debian-source"
92 changes: 76 additions & 16 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ on:
permissions:
contents: read

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
build:
name: Build ${{ matrix.target }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
Expand All @@ -33,7 +37,7 @@ jobs:
ctl_artifact: tntctl-darwin-arm64

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Verify release tag matches source version
run: scripts/check_release_ref.sh "${GITHUB_REF_NAME}"
Expand Down Expand Up @@ -91,40 +95,91 @@ jobs:
${{ matrix.artifact }}
${{ matrix.ctl_artifact }}

source-archive:
name: Source archive
runs-on: ubuntu-24.04

steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Verify release tag matches source version
run: scripts/check_release_ref.sh "${GITHUB_REF_NAME}"

- name: Build source archive
run: |
set -eu
version=$(sed -n 's/^#define TNT_VERSION "\([^"]*\)".*/\1/p' include/common.h)
commit=$(git rev-list -n 1 "${GITHUB_REF_NAME}")
mkdir -p dist
git archive --format=tar.gz --prefix="TNT-${version}/" \
-o "dist/tnt-chat-v${version}-source.tar.gz" "$commit"
tar -tzf "dist/tnt-chat-v${version}-source.tar.gz" >/dev/null
tar -tzf "dist/tnt-chat-v${version}-source.tar.gz" | grep -q "^TNT-${version}/LICENSE$"
tar -tzf "dist/tnt-chat-v${version}-source.tar.gz" | grep -q "^TNT-${version}/packaging/README.md$"
sha256sum "dist/tnt-chat-v${version}-source.tar.gz"

- name: Upload source archive
uses: actions/upload-artifact@v4
with:
name: tnt-chat-source
path: dist/tnt-chat-v*-source.tar.gz

artifact-gate:
name: Release artifact gate
needs: [build, source-archive]
runs-on: ubuntu-24.04

steps:
- uses: actions/checkout@v6

- name: Verify release tag matches source version
run: scripts/check_release_ref.sh "${GITHUB_REF_NAME}"

- name: Download build artifacts
uses: actions/download-artifact@v4
with:
path: ./artifacts

- name: Verify and package release assets
run: scripts/package_release_assets.sh ./artifacts ./dist/release-assets

- name: Upload release asset bundle
uses: actions/upload-artifact@v4
with:
name: release-assets
path: dist/release-assets/*

release:
needs: build
needs: [artifact-gate, source-archive]
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Verify release tag matches source version
run: scripts/check_release_ref.sh "${GITHUB_REF_NAME}"

- name: Download all artifacts
- name: Download release asset bundle
uses: actions/download-artifact@v4
with:
path: ./artifacts
name: release-assets
path: ./release-assets

- name: Create checksums
- name: Verify release checksums
run: |
cd artifacts
: > checksums.txt
for artifact in */tnt-* */tntctl-*; do
[ -f "$artifact" ] || continue
sha256sum "$artifact" | sed "s# $artifact# $(basename "$artifact")#" >> checksums.txt
done
cd release-assets
sha256sum -c checksums.txt
cat checksums.txt

- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: |
artifacts/*/tnt-*
artifacts/*/tntctl-*
artifacts/checksums.txt
release-assets/*
body: |
## Installation

Expand Down Expand Up @@ -190,11 +245,16 @@ jobs:
sha256sum -c checksums.txt --ignore-missing

# macOS
for f in tnt-* tntctl-*; do
for f in tnt-* tntctl-* tnt-chat-*-source.tar.gz; do
grep " $f$" checksums.txt | shasum -a 256 -c -
done
```

The release also includes `tnt-chat-${{ github.ref_name }}-source.tar.gz`
for package-manager recipes. Verify it with the same `checksums.txt`
before updating Arch, Homebrew, Debian, Ubuntu, or container package
metadata.

## What's Changed
See [docs/CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ github.ref_name }}/docs/CHANGELOG.md)
draft: true
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ script-test: all
@cd tests && ./test_docs_help_surface.sh
@cd tests && ./test_logrotate.sh
@cd tests && ./test_message_log_tool.sh
@cd tests && ./test_release_artifact_gate.sh

integration-test: all
@echo "Running integration tests..."
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -398,14 +398,14 @@ make release-check
Longer local preflight can opt into runtime soak and slow-client coverage:

```sh
RUN_SOAK=1 RUN_SLOW_CLIENT=1 make release-check
RUN_INTEGRATION=1 RUN_SOAK=1 RUN_SLOW_CLIENT=1 make release-check
```

Before publishing package recipes, download the final GitHub source archive,
Before publishing package recipes, download the explicit release source archive,
replace placeholder checksums, and run:

```sh
SOURCE_TARBALL=dist/tnt-chat-vX.Y.Z.tar.gz make package-publish-check
SOURCE_TARBALL=dist/tnt-chat-vX.Y.Z-source.tar.gz make package-publish-check
```

## Files
Expand Down
9 changes: 7 additions & 2 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@
- Added a release tag/version guard used by the GitHub release workflow, so a
`vX.Y.Z` tag must match `TNT_VERSION` before release assets are built.
- Added `make package-publish-check` for verifying Arch/Homebrew source
checksums against the final GitHub source archive after a tag exists.
checksums against the explicit release source archive after a tag exists.
- Added a release artifact gate that bundles Linux/macOS binaries, the explicit
release source archive, and `checksums.txt` before opening the draft release.
- Added CI governance layers for fast PR checks, release-branch validation,
extended runtime validation, container portability builds, and package recipe
validation.
- Added a `config_defaults` module and unit coverage for runtime default
values, env keys, and accepted numeric ranges.
- Added a dedicated `tntctl_text` module with unit coverage for local
Expand Down Expand Up @@ -53,7 +58,7 @@
matches, avoiding the impression that the pager is a complete result set.
- Release checks now separate tag/source-archive readiness from package-manager
checksum publishing, avoiding self-referential checksum requirements before
the final GitHub source archive exists.
the explicit release source archive exists.
- `tntctl --help` now gets its exec command list from `exec_catalog`, reducing
duplicate command metadata between the local wrapper and SSH exec mode.
- Updated `tnt(1)` to document the current TUI search and pager keys, and
Expand Down
Loading