Skip to content

Commit e7d9fbc

Browse files
committed
chore: prepare 0.2.0 release packaging
Bump termviz to 0.2.0, add the Linux x64 npm binary wrapper, and add a tag-driven release workflow for static artifact, crates.io, and npm publishing.\n\nSplit the plot pan atlas prefetch code out of the frame cache module and update release documentation, changelog, README installation notes, and local release verification smoke checks.
1 parent ce53007 commit e7d9fbc

15 files changed

Lines changed: 635 additions & 193 deletions

File tree

.github/workflows/release.yml

Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
workflow_dispatch:
8+
inputs:
9+
tag:
10+
description: "Release tag to publish, for example v0.2.0"
11+
required: true
12+
type: string
13+
14+
env:
15+
RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || github.ref_name }}
16+
LINUX_X64_TARGET: x86_64-unknown-linux-musl
17+
18+
permissions:
19+
contents: read
20+
21+
jobs:
22+
build-linux-x64:
23+
runs-on: ubuntu-latest
24+
outputs:
25+
version: ${{ steps.version.outputs.version }}
26+
tag: ${{ steps.version.outputs.tag }}
27+
steps:
28+
- uses: actions/checkout@v5
29+
with:
30+
ref: ${{ env.RELEASE_TAG }}
31+
32+
- uses: dtolnay/rust-toolchain@stable
33+
with:
34+
components: rustfmt, clippy
35+
36+
- name: Install Linux x64 static build target
37+
shell: bash
38+
run: |
39+
set -euo pipefail
40+
sudo apt-get update
41+
sudo apt-get install -y musl-tools binutils file
42+
rustup target add "$LINUX_X64_TARGET"
43+
44+
- name: Validate tag and package versions
45+
id: version
46+
shell: bash
47+
run: |
48+
set -euo pipefail
49+
version="$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n 1)"
50+
npm_version="$(node -p "require('./npm/termviz/package.json').version")"
51+
tag="${RELEASE_TAG#v}"
52+
53+
test "$version" = "$tag"
54+
test "$npm_version" = "$version"
55+
56+
echo "version=$version" >> "$GITHUB_OUTPUT"
57+
echo "tag=$RELEASE_TAG" >> "$GITHUB_OUTPUT"
58+
59+
- run: cargo fmt --check
60+
- run: cargo test --locked
61+
- run: cargo clippy --all-targets --locked -- -D warnings
62+
- run: cargo build --release --locked --target "$LINUX_X64_TARGET"
63+
64+
- name: Package Linux x64 static binary
65+
shell: bash
66+
run: |
67+
set -euo pipefail
68+
mkdir -p dist/termviz-linux-x64
69+
cp "target/$LINUX_X64_TARGET/release/termviz" dist/termviz-linux-x64/
70+
cp "target/$LINUX_X64_TARGET/release/termviz" dist/termviz
71+
cp README.md LICENSE dist/termviz-linux-x64/
72+
file dist/termviz-linux-x64/termviz
73+
if readelf -l dist/termviz-linux-x64/termviz | grep -q "Requesting program interpreter"; then
74+
echo "Expected a static Linux x64 binary without a glibc runtime dependency." >&2
75+
exit 1
76+
fi
77+
dist/termviz-linux-x64/termviz --version
78+
tar -C dist -czf "dist/termviz-linux-x64.tar.gz" termviz-linux-x64
79+
80+
- uses: actions/upload-artifact@v7
81+
with:
82+
name: termviz-linux-x64
83+
path: |
84+
dist/termviz-linux-x64.tar.gz
85+
dist/termviz
86+
87+
github-release:
88+
runs-on: ubuntu-latest
89+
needs: build-linux-x64
90+
permissions:
91+
contents: write
92+
steps:
93+
- uses: actions/checkout@v5
94+
with:
95+
ref: ${{ needs.build-linux-x64.outputs.tag }}
96+
97+
- uses: actions/download-artifact@v8
98+
with:
99+
name: termviz-linux-x64
100+
path: dist
101+
102+
- name: Create checksums
103+
shell: bash
104+
run: |
105+
set -euo pipefail
106+
cd dist
107+
sha256sum termviz-linux-x64.tar.gz > sha256sums.txt
108+
109+
- name: Extract release notes
110+
id: release-notes
111+
env:
112+
TAG: ${{ needs.build-linux-x64.outputs.tag }}
113+
shell: bash
114+
run: |
115+
set -euo pipefail
116+
version="${TAG#v}"
117+
notes_file="$RUNNER_TEMP/release-notes.md"
118+
awk -v version="$version" '
119+
$0 == "## [" version "]" || $0 ~ "^## \\[" version "\\] - " {
120+
found = 1
121+
next
122+
}
123+
found && /^## / {
124+
exit
125+
}
126+
found {
127+
print
128+
}
129+
' CHANGELOG.md > "$notes_file"
130+
131+
if ! grep -q '[^[:space:]]' "$notes_file"; then
132+
echo "CHANGELOG.md is missing a non-empty section for $TAG." >&2
133+
exit 1
134+
fi
135+
136+
echo "file=$notes_file" >> "$GITHUB_OUTPUT"
137+
138+
- name: Publish GitHub Release
139+
env:
140+
GH_TOKEN: ${{ github.token }}
141+
GH_REPO: ${{ github.repository }}
142+
TAG: ${{ needs.build-linux-x64.outputs.tag }}
143+
NOTES_FILE: ${{ steps.release-notes.outputs.file }}
144+
shell: bash
145+
run: |
146+
set -euo pipefail
147+
if gh release view "$TAG" --repo "$GH_REPO" >/dev/null 2>&1; then
148+
gh release edit "$TAG" --repo "$GH_REPO" --notes-file "$NOTES_FILE"
149+
gh release upload "$TAG" dist/termviz-linux-x64.tar.gz dist/sha256sums.txt --clobber --repo "$GH_REPO"
150+
else
151+
gh release create "$TAG" dist/termviz-linux-x64.tar.gz dist/sha256sums.txt \
152+
--repo "$GH_REPO" \
153+
--verify-tag \
154+
--title "$TAG" \
155+
--notes-file "$NOTES_FILE"
156+
fi
157+
158+
crates-io:
159+
runs-on: ubuntu-latest
160+
needs: build-linux-x64
161+
env:
162+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
163+
steps:
164+
- uses: actions/checkout@v5
165+
with:
166+
ref: ${{ needs.build-linux-x64.outputs.tag }}
167+
- uses: dtolnay/rust-toolchain@stable
168+
169+
- name: Check crates.io package version
170+
id: crates-published
171+
env:
172+
VERSION: ${{ needs.build-linux-x64.outputs.version }}
173+
shell: bash
174+
run: |
175+
set -euo pipefail
176+
status="$(
177+
curl -sS -o /tmp/crate-version.json -w '%{http_code}' \
178+
-H "User-Agent: termviz-release (https://github.com/siriusctrl/termviz)" \
179+
"https://crates.io/api/v1/crates/termviz/$VERSION"
180+
)"
181+
case "$status" in
182+
200)
183+
echo "published=true" >> "$GITHUB_OUTPUT"
184+
;;
185+
404)
186+
echo "published=false" >> "$GITHUB_OUTPUT"
187+
;;
188+
*)
189+
echo "crates.io version check failed with HTTP $status"
190+
sed -n '1,120p' /tmp/crate-version.json
191+
exit 1
192+
;;
193+
esac
194+
195+
- name: Dry-run crates.io package
196+
run: cargo publish --dry-run --locked
197+
198+
- name: Publish to crates.io
199+
if: env.CARGO_REGISTRY_TOKEN != '' && steps.crates-published.outputs.published != 'true'
200+
run: cargo publish --locked --token "$CARGO_REGISTRY_TOKEN"
201+
202+
- name: Skip already published crates.io version
203+
if: steps.crates-published.outputs.published == 'true'
204+
run: echo "termviz ${{ needs.build-linux-x64.outputs.version }} is already published on crates.io."
205+
206+
- name: Skip crates.io publish
207+
if: env.CARGO_REGISTRY_TOKEN == '' && steps.crates-published.outputs.published != 'true'
208+
run: echo "CARGO_REGISTRY_TOKEN is not configured; skipped crates.io publish."
209+
210+
npm:
211+
runs-on: ubuntu-latest
212+
needs:
213+
- build-linux-x64
214+
- crates-io
215+
permissions:
216+
contents: read
217+
id-token: write
218+
env:
219+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
220+
steps:
221+
- uses: actions/checkout@v5
222+
with:
223+
ref: ${{ needs.build-linux-x64.outputs.tag }}
224+
225+
- uses: actions/download-artifact@v8
226+
with:
227+
name: termviz-linux-x64
228+
path: dist
229+
230+
- uses: actions/setup-node@v6
231+
with:
232+
node-version: "24"
233+
registry-url: "https://registry.npmjs.org"
234+
235+
- name: Check npm package version
236+
id: npm-published
237+
env:
238+
VERSION: ${{ needs.build-linux-x64.outputs.version }}
239+
shell: bash
240+
run: |
241+
set -euo pipefail
242+
status=0
243+
npm view "termviz@$VERSION" version >/tmp/npm-version.txt 2>/tmp/npm-view.err || status=$?
244+
if [ "$status" = "0" ]; then
245+
echo "published=true" >> "$GITHUB_OUTPUT"
246+
elif grep -q "E404" /tmp/npm-view.err; then
247+
echo "published=false" >> "$GITHUB_OUTPUT"
248+
else
249+
sed -n '1,120p' /tmp/npm-view.err
250+
exit "$status"
251+
fi
252+
253+
- name: Prepare npm package
254+
if: steps.npm-published.outputs.published != 'true'
255+
shell: bash
256+
run: |
257+
set -euo pipefail
258+
mkdir -p npm/termviz/vendor
259+
cp dist/termviz npm/termviz/vendor/termviz
260+
cp LICENSE npm/termviz/LICENSE
261+
chmod 755 npm/termviz/vendor/termviz
262+
node npm/termviz/bin/termviz.js --version
263+
npm pack --dry-run ./npm/termviz
264+
265+
- name: Publish to npm
266+
if: env.NODE_AUTH_TOKEN != '' && steps.npm-published.outputs.published != 'true'
267+
working-directory: npm/termviz
268+
run: npm publish --provenance --access public
269+
270+
- name: Skip already published npm version
271+
if: steps.npm-published.outputs.published == 'true'
272+
run: echo "termviz ${{ needs.build-linux-x64.outputs.version }} is already published on npm."
273+
274+
- name: Skip npm publish
275+
if: env.NODE_AUTH_TOKEN == '' && steps.npm-published.outputs.published != 'true'
276+
run: echo "NPM_TOKEN is not configured; skipped npm publish."

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
/.DS_Store
33
*.swp
44
*.swo
5+
/npm/termviz/LICENSE
6+
/npm/termviz/vendor/

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,15 @@ matching `## [X.Y.Z]` section before the release tag is pushed.
88

99
## [Unreleased]
1010

11+
## [0.2.0] - 2026-06-16
12+
1113
### Added
1214

15+
- Add a Linux x64 npm package wrapper that ships a prebuilt static `termviz`
16+
binary for `npm install -g termviz`.
17+
- Add a tag-driven release workflow that builds a static Linux x64 artifact,
18+
publishes GitHub Release assets, runs a crates.io dry-run, and publishes npm
19+
and crates.io when registry tokens are configured.
1320
- Default redirected/export output to PNG when no `--output-format` is provided,
1421
while still inferring JSON/ANSI/SVG/PNG from optional `--output` extensions
1522
when they are recognized.

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "termviz"
3-
version = "0.1.0"
3+
version = "0.2.0"
44
edition = "2024"
55
rust-version = "1.85"
66
description = "Terminal-first viewer for images and plots"
@@ -9,6 +9,7 @@ repository = "https://github.com/siriusctrl/termviz"
99
readme = "README.md"
1010
keywords = ["terminal", "image", "plot", "viewer", "cli"]
1111
categories = ["command-line-utilities", "visualization"]
12+
exclude = [".github/", "npm/"]
1213

1314
[dependencies]
1415
ab_glyph = "0.2.32"

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,18 @@ metadata and explicit exports.
88

99
## Quick Start
1010

11+
Install with Cargo:
12+
13+
```sh
14+
cargo install termviz
15+
```
16+
17+
Linux x64 users can also install the prebuilt static binary wrapper from npm:
18+
19+
```sh
20+
npm install -g termviz
21+
```
22+
1123
```sh
1224
termviz image.png
1325
termviz image.png --inspect

docs/INDEX.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Read these when the task matches:
2020
- version and tag policy
2121
- changelog and release notes policy
2222
- GitHub Release artifacts and checksums
23-
- crates.io publishing and npm deferral
23+
- crates.io and npm publishing
2424
- `docs/visual-verification.md`
2525
- PTY recording artifacts
2626
- keyframe/contact-sheet inspection
@@ -57,8 +57,8 @@ Code orientation:
5757
and layout helpers.
5858
- `src/viewer.rs` owns the shared TTY lifecycle and viewer dispatch.
5959
- `src/viewer/` owns terminal-facing image and plot viewer modes.
60-
- `src/viewer/plot/` owns the interactive plot loop plus focused state,
61-
event, cache, and chrome modules.
60+
- `src/viewer/plot/` owns the interactive plot loop plus focused state, event,
61+
cache, pan-atlas prefetch, and chrome modules.
6262
- `src/export.rs` owns explicit non-interactive export.
6363
- `tests/cli.rs` covers black-box CLI behavior through the compiled binary.
6464
- `scripts/bench-*.sh` contains local performance entry points. Start with

0 commit comments

Comments
 (0)