diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index de2c196..d51fc4f 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -93,10 +93,14 @@ jobs: for t in linux-x64 linux-arm64 darwin-x64 darwin-arm64; do cp "sidecars/anfra-node-$t" internal/sidecar/assets/anfra-node cp "sidecars/canal-query-$t" internal/sidecar/assets/canal-query + # -s -w strips the host's symbol table + DWARF (Phase 0). GOOS="${OS[$t]}" GOARCH="${ARCH[$t]}" go build -tags embed_sidecar \ - -ldflags "-X github.com/holistics/anfra/internal/meta.Version=$VERSION" \ + -ldflags "-s -w -X github.com/holistics/anfra/internal/meta.Version=$VERSION" \ -o "release/anfra-$t" ./cmd/anfra - file "release/anfra-$t" || true + # Transport compression (Phase 1, see compression.md): publish only the + # .gz. The embed stays uncompressed so the binary remains delta-friendly. + gzip -9 "release/anfra-$t" # replaces anfra-$t with anfra-$t.gz + file "release/anfra-$t.gz" || true done ls -la release diff --git a/CHANGELOG.md b/CHANGELOG.md index f81dd6b..732de0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,37 @@ -## [](https://github.com/holistics/anfra/compare/anfra-v0.1.0...anfra-v) (2026-07-22) +## [0.3.0](https://github.com/holistics/anfra/compare/anfra-v0.2.0...anfra-v0.3.0) (2026-07-23) + +### Build + +* bump canal-query 2.13.0 ([63048f3](https://github.com/holistics/anfra/commit/63048f35cdf0021c4fc15677108afc12d0992e82)) +* compress download ([25cea57](https://github.com/holistics/anfra/commit/25cea57460cc341ffb5bb8c17305a90322c8507c)) +## [0.2.0](https://github.com/holistics/anfra/compare/anfra-v0.1.0...anfra-v0.2.0) (2026-07-22) ### Features -* auto update mechanism ([180d9a2](https://github.com/holistics/anfra/commit/180d9a227ebbaaed1bebde90066587a97559cb13)) +* auto update mechanism ([258a94c](https://github.com/holistics/anfra/commit/258a94cf8ef08dccec2cebbae6f699c9224f43ae)) ### Build -* install.sh script ([a2c9ed6](https://github.com/holistics/anfra/commit/a2c9ed656a072f24ac08d41a45b205207a287125)) -# Changelog +* install.sh script ([24de3d9](https://github.com/holistics/anfra/commit/24de3d98b96c23b458284c23a71f3af2038a3d0f)) + +## [0.1.0](https://github.com/holistics/anfra/compare/c567bd9d4eb4601ca1480de59d02c363ee6f19cc...anfra-v0.1.0) (2026-07-21) + +### Features + +* implement serve ([1e2fb63](https://github.com/holistics/anfra/commit/1e2fb63b1634ae7052f5ef6b6bfbec2a1deae04a)) +* patch aql limit with truncate_rows ([2fd2a90](https://github.com/holistics/anfra/commit/2fd2a90a9075b8732903c72c8c80bef3821dafa4)) +* query command ([c567bd9](https://github.com/holistics/anfra/commit/c567bd9d4eb4601ca1480de59d02c363ee6f19cc)) +* remove validate --aql, add arg shorthands ([70bf1e2](https://github.com/holistics/anfra/commit/70bf1e29f05153b9ffab7933e4040d9807502e4c)) +* validate command ([fa0ce05](https://github.com/holistics/anfra/commit/fa0ce05db16a01b8b853e03cbc63bd3b3f7628d2)) + +### Bug Fixes + +* proper validation for AQL ([d633c21](https://github.com/holistics/anfra/commit/d633c21bbe94a274d7e8e66f71f67c32f368a132)) + +### Build + +* bump anfra_node 0.0.3 ([c9ecb63](https://github.com/holistics/anfra/commit/c9ecb63527ec6b78779afb4fc82c6b7b985b338f)) + +### Performance Improvements -All notable changes to anfra are documented here, generated from -[conventional commits](https://www.conventionalcommits.org/) via `pnpm bump` -(or `pnpm changelog`). +* enable canal query connection pool when doing serve ([a9a8f25](https://github.com/holistics/anfra/commit/a9a8f250e7a73ce6fb06c98175fc2fd3ea10cb78)) diff --git a/cmd/anfra/update.go b/cmd/anfra/update.go index b37c948..0ba746d 100644 --- a/cmd/anfra/update.go +++ b/cmd/anfra/update.go @@ -47,7 +47,7 @@ func runUpdate(ctx context.Context, checkOnly bool) error { return nil } - fmt.Printf("Downloading %s (~250 MB)...\n", rel.Tag) + fmt.Printf("Downloading %s...\n", rel.Tag) // Show a progress line only on an interactive terminal; stay silent when // output is piped/captured (agent, CI). var progress io.Writer diff --git a/install.sh b/install.sh index e5657d3..85a3c77 100755 --- a/install.sh +++ b/install.sh @@ -26,6 +26,16 @@ INSTALL_DIR="${ANFRA_INSTALL_DIR:-${HOME}/.anfra/bin}" err() { echo "anfra-install: $*" >&2; exit 1; } +# --- required tools (fail early with a clear message, not mid-run) --- +command -v curl >/dev/null 2>&1 || err "curl is required but not found" +if command -v gunzip >/dev/null 2>&1; then + gunzip_cmd="gunzip -c" +elif command -v gzip >/dev/null 2>&1; then + gunzip_cmd="gzip -dc" +else + err "gzip/gunzip is required to decompress the download but was not found" +fi + # --- detect platform, mapped to the release asset names (anfra--) --- os="$(uname -s | tr '[:upper:]' '[:lower:]')" case "$os" in @@ -41,7 +51,9 @@ case "$arch" in *) err "unsupported architecture: $arch" ;; esac -asset="${BIN_NAME}-${os}-${arch}" +# Release binaries are published gzip-compressed for transport (see the anfra +# compression plan); we gunzip after download. +asset="${BIN_NAME}-${os}-${arch}.gz" # --- resolve the download URL (avoid the GitHub API + its 60 req/hr limit) --- # The /releases/latest/download/ and /releases/download// @@ -53,13 +65,16 @@ else url="https://github.com/${REPO}/releases/latest/download/${asset}" fi -# --- download --- +# --- download + decompress --- tmp="$(mktemp -d)" trap 'rm -rf "$tmp"' EXIT -echo "Downloading ${asset} (~250 MB) for ${os}/${arch}..." -if ! curl -fL -o "${tmp}/${BIN_NAME}" "$url"; then +echo "Downloading ${asset} for ${os}/${arch}..." +if ! curl -fL -o "${tmp}/${BIN_NAME}.gz" "$url"; then err "download failed from ${url} (is the release published for this platform?)" fi +if ! $gunzip_cmd "${tmp}/${BIN_NAME}.gz" > "${tmp}/${BIN_NAME}"; then + err "failed to decompress ${asset}" +fi # Log the checksum for the record (TOFU; no verification yet). if command -v sha256sum >/dev/null 2>&1; then diff --git a/internal/update/update.go b/internal/update/update.go index 15b0125..cbb241f 100644 --- a/internal/update/update.go +++ b/internal/update/update.go @@ -8,6 +8,7 @@ package update import ( + "compress/gzip" "context" "encoding/json" "fmt" @@ -111,10 +112,13 @@ func get(ctx context.Context, url, accept string, timeout time.Duration) (*http. // Latest fetches the newest release and resolves the asset for this platform. func Latest(ctx context.Context) (*Release, error) { - want, err := assetName() + base, err := assetName() if err != nil { return nil, err } + // Release binaries are published gzip-compressed for transport (see the + // compression plan); Apply decompresses on the way in. + want := base + ".gz" resp, err := get(ctx, fmt.Sprintf("%s/repos/%s/releases/latest", apiBase, repoSlug), "application/vnd.github+json", lookupTimeout) if err != nil { return nil, fmt.Errorf("check latest release: %w", err) @@ -179,11 +183,18 @@ func Apply(ctx context.Context, r *Release, progress io.Writer) error { if resp.StatusCode != http.StatusOK { return fmt.Errorf("download %s: GitHub returned %s", r.Tag, resp.Status) } - var body io.Reader = resp.Body + // Progress tracks the compressed bytes actually transferred; gzip.Reader then + // decompresses to the real binary for the self-replace (embed stays uncompressed). + var src io.Reader = resp.Body if progress != nil { - body = &progressReader{r: resp.Body, total: resp.ContentLength, w: progress} + src = &progressReader{r: resp.Body, total: resp.ContentLength, w: progress} } - if err := selfupdate.Apply(body, selfupdate.Options{}); err != nil { + gz, err := gzip.NewReader(src) + if err != nil { + return fmt.Errorf("decompress %s: %w", r.Tag, err) + } + defer gz.Close() + if err := selfupdate.Apply(gz, selfupdate.Options{}); err != nil { if rerr := selfupdate.RollbackError(err); rerr != nil { return fmt.Errorf("update failed and rollback also failed: %v (rollback: %v)", err, rerr) } diff --git a/manifest.yml b/manifest.yml index c12a797..95a26be 100644 --- a/manifest.yml +++ b/manifest.yml @@ -4,7 +4,7 @@ # which triggers build_release.yml to download the pinned sidecars, cross-build, # and publish. Always bump `version` when changing a pin — otherwise the tag # already exists and no new release is cut. -version: 0.2.0 +version: 0.3.0 sidecars: anfra_node: anfra-node-v0.0.3 # holistics/holistics-core release tag (anfra_node_build_binaries.yml) - canal_query: query-v2.12.0 # holistics/canal release tag (build_and_release_binaries.yml) + canal_query: query-v2.13.0 # holistics/canal release tag (build_and_release_binaries.yml) diff --git a/scripts/bump.sh b/scripts/bump.sh index f815ff3..1a9c66b 100755 --- a/scripts/bump.sh +++ b/scripts/bump.sh @@ -11,9 +11,20 @@ version="${1:?usage: pnpm bump e.g. pnpm bump 0.2.0}" # manifest.yml is the single source of truth for the release version. sed -i.bak -E "s/^version: .*/version: ${version}/" manifest.yml && rm -f manifest.yml.bak -# Prepend the changes since the last anfra-v* tag to the changelog. +# Prepend the changes since the last anfra-v* tag to the changelog. The pending +# release version is passed via a context file (mirrors canal's bump) — otherwise +# conventional-changelog reads it from package.json (which has none) and emits an +# empty "## []" header. git fetch --tags --quiet -pnpm run changelog +# Pass the pending version via a context file (mirrors canal's bump). It must end +# in .json — conventional-changelog loads -c by file extension. +ctx="/tmp/anfra-bump-context.json" +printf '{ "version": "%s" }\n' "$version" > "$ctx" +pnpm exec conventional-changelog \ + -n conventional-changelog.config.mjs \ + -c "$ctx" \ + -i CHANGELOG.md -s \ + -t anfra-v echo "Bumped manifest.yml -> ${version} and updated CHANGELOG.md." echo "Review both, commit, and merge to main to cut anfra-v${version}."