diff --git a/.gitignore b/.gitignore index 505b1d8..ce4bc6c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ test.log tests/unit/test_utf8 tests/unit/test_message tests/unit/test_chat_room +tests/unit/test_history_view diff --git a/Makefile b/Makefile index 8231fbb..4fd8e42 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ BINDIR ?= $(PREFIX)/bin MANDIR ?= $(PREFIX)/share/man SYSTEMD_UNIT_DIR ?= $(PREFIX)/lib/systemd/system -.PHONY: all clean install install-systemd uninstall uninstall-systemd debug release asan valgrind check test unit-test info +.PHONY: all clean install install-systemd uninstall uninstall-systemd debug release release-check release-check-strict asan valgrind check test unit-test info all: $(TARGET) @@ -74,6 +74,12 @@ release: CFLAGS += -O3 -DNDEBUG release: clean $(TARGET) strip $(TARGET) +release-check: + ./scripts/release_check.sh + +release-check-strict: + ./scripts/release_check.sh --strict + asan: CFLAGS += -g -fsanitize=address -fno-omit-frame-pointer asan: LDFLAGS += -fsanitize=address asan: clean $(TARGET) diff --git a/README.md b/README.md index 7b93aa7..d5e3774 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,7 @@ ssh -p 2222 chat.m1ng.space post "/me deploys v2.0" make # standard build make debug # debug build (with symbols) make asan # AddressSanitizer build +make release-check # local release/package preflight make check # static analysis (cppcheck) make clean # clean build artifacts ``` @@ -248,6 +249,7 @@ TNT/ ├── include/ # header files ├── tests/ # test scripts ├── docs/ # documentation +├── packaging/ # package-manager drafts and release checklist ├── scripts/ # operational scripts ├── Makefile # build configuration └── README.md # this file @@ -289,6 +291,23 @@ CMD ["tnt"] See [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md) for details. +## Packaging + +Package-manager drafts live in [packaging/](packaging/). Current targets are +Arch/AUR (`tnt-chat`), Homebrew tap formula, and Ubuntu PPA notes. + +Before preparing a release locally: + +```sh +make release-check +``` + +Before publishing package recipes, replace placeholder checksums and run: + +```sh +make release-check-strict +``` + ## Files ``` diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index b12dd75..73aea34 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -30,6 +30,8 @@ and `:support`. - `:support` is now task-oriented around common user goals, and mistyped commands suggest the nearest known command when possible. +- Added a local `make release-check` preflight for release/package validation + without tagging, publishing, or deploying. ## 2026-05-18 - Interactive input polish diff --git a/docs/CICD.md b/docs/CICD.md index c775b23..861dd6c 100644 --- a/docs/CICD.md +++ b/docs/CICD.md @@ -17,19 +17,30 @@ into production or restart services on push. CREATING RELEASES ----------------- -1. Update version in CHANGELOG.md +1. Update version metadata: + - include/common.h + - tnt.1 + - docs/CHANGELOG.md + - packaging/arch/PKGBUILD + - packaging/homebrew/tnt-chat.rb -2. Create and push tag: +2. Run the local preflight: + make release-check + +3. Replace package checksum placeholders and run: + make release-check-strict + +4. Create and push tag: git tag v1.0.0 git push origin v1.0.0 -3. GitHub Actions automatically: +5. GitHub Actions automatically: - Builds binaries (Linux/macOS, AMD64/ARM64) - Creates release - Uploads binaries - Generates checksums -4. Release appears at: +6. Release appears at: https://github.com/m1ngsama/TNT/releases @@ -84,7 +95,7 @@ PLATFORMS SUPPORTED EXAMPLE WORKFLOW ---------------- # Local development -make && make asan +make && make asan && make release-check ./tnt # Create release diff --git a/packaging/README.md b/packaging/README.md index cae9bde..63e7a83 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -19,14 +19,16 @@ any public registry. 5. Verify package contents in an isolated directory: ```sh - make clean - make - tmpdir="$(mktemp -d)" - make DESTDIR="$tmpdir" PREFIX=/usr install - find "$tmpdir" -type f | sort + make release-check ``` -6. Submit packages manually: +6. Before submitting package recipes, replace checksum placeholders and run: + + ```sh + make release-check-strict + ``` + +7. Submit packages manually: - Arch: upload `PKGBUILD` and generated `.SRCINFO` to AUR. - Homebrew: open a PR to the project tap, or later Homebrew core if eligible. - Ubuntu: build Debian source packages and upload to a Launchpad PPA. diff --git a/scripts/release_check.sh b/scripts/release_check.sh new file mode 100755 index 0000000..aece2ff --- /dev/null +++ b/scripts/release_check.sh @@ -0,0 +1,123 @@ +#!/bin/sh +# Local release preflight. This never tags, pushes, publishes, or deploys. + +set -eu + +STRICT=0 + +usage() { + cat <<'USAGE' +Usage: scripts/release_check.sh [--strict] + +Default checks: + - version metadata alignment + - clean build + - unit tests + - staged install layout with PREFIX=/usr and DESTDIR + - Arch/Homebrew packaging syntax + +Environment: + RUN_INTEGRATION=1 also run full make test + PORT=12720 base port for integration tests + +Strict checks additionally require real package checksums and a local vX.Y.Z tag. +USAGE +} + +while [ "$#" -gt 0 ]; do + case "$1" in + --strict) + STRICT=1 + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "unknown argument: $1" >&2 + usage >&2 + exit 2 + ;; + esac + shift +done + +ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) +cd "$ROOT" + +fail() { + echo "release-check: $*" >&2 + exit 1 +} + +step() { + printf '\n==> %s\n' "$*" +} + +version=$(sed -n 's/^#define TNT_VERSION "\([^"]*\)".*/\1/p' include/common.h) +[ -n "$version" ] || fail "could not read TNT_VERSION from include/common.h" + +step "checking version metadata for $version" +grep -q "\"TNT $version\"" tnt.1 || + fail "tnt.1 does not mention TNT $version" +grep -q "^pkgver=$version$" packaging/arch/PKGBUILD || + fail "packaging/arch/PKGBUILD pkgver does not match $version" +grep -q "v${version}.tar.gz" packaging/homebrew/tnt-chat.rb || + fail "packaging/homebrew/tnt-chat.rb URL does not match v$version" + +step "building" +make clean +make + +actual_version=$(./tnt --version) +[ "$actual_version" = "tnt $version" ] || + fail "binary version mismatch: expected 'tnt $version', got '$actual_version'" + +step "running unit tests" +make -C tests/unit clean +make -C tests/unit run + +if [ "${RUN_INTEGRATION:-0}" = "1" ]; then + step "running full integration tests" + make test PORT="${PORT:-12720}" +fi + +tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/tnt-release-check.XXXXXX") +cleanup() { + rm -rf "$tmpdir" +} +trap cleanup EXIT INT TERM + +step "checking staged install layout" +make DESTDIR="$tmpdir" PREFIX=/usr install +make DESTDIR="$tmpdir" PREFIX=/usr install-systemd + +[ -x "$tmpdir/usr/bin/tnt" ] || fail "missing executable: /usr/bin/tnt" +[ -f "$tmpdir/usr/share/man/man1/tnt.1" ] || fail "missing manpage: /usr/share/man/man1/tnt.1" +[ -f "$tmpdir/usr/lib/systemd/system/tnt.service" ] || + fail "missing systemd unit: /usr/lib/systemd/system/tnt.service" + +step "checking packaging syntax" +if command -v bash >/dev/null 2>&1; then + bash -n packaging/arch/PKGBUILD +else + echo "bash not found; skipping PKGBUILD syntax check" +fi + +if command -v ruby >/dev/null 2>&1; then + ruby -c packaging/homebrew/tnt-chat.rb +else + echo "ruby not found; skipping Homebrew formula syntax check" +fi + +if [ "$STRICT" -eq 1 ]; then + step "checking strict release gates" + ! grep -q "sha256sums=('SKIP')" packaging/arch/PKGBUILD || + fail "replace PKGBUILD sha256sums before strict release" + ! grep -q "REPLACE_WITH_RELEASE_TARBALL_SHA256" packaging/homebrew/tnt-chat.rb || + fail "replace Homebrew sha256 before strict release" + git rev-parse -q --verify "refs/tags/v$version" >/dev/null || + fail "missing local tag v$version" +fi + +step "release preflight passed"