Skip to content

Commit 7d10ec2

Browse files
committed
Harden install layout before release automation
Package smoke tests now prove the stable .deb asset and installed file layout before a release is published. Runtime path resolution is exposed through the unified CLI so snippets and fallbacks can stop guessing source versus package paths. Constraint: CI uses locked Rust builds and must validate package layout in a clean Ubuntu install. Rejected: Defer path and package checks to manual release review | the review already found shippable layout drift. Confidence: medium Scope-risk: moderate Directive: Keep flashpaste paths as the contract for scripts, snippets, and package smoke tests. Tested: cargo fmt --manifest-path rs/Cargo.toml --all --check; RUSTC_WRAPPER= cargo test --locked --offline --manifest-path rs/Cargo.toml -p flashpaste-common --lib; RUSTC_WRAPPER= cargo check --locked --offline --manifest-path rs/Cargo.toml -p flashpaste; bash -n bin/*.sh install.sh bootstrap.sh packaging/build-deb.sh packaging/package-smoke.sh AGENTS-release-check.sh; git diff --check Not-tested: package-smoke docker install locally; GitHub Actions release workflow locally
1 parent daee02d commit 7d10ec2

36 files changed

Lines changed: 3841 additions & 109 deletions

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ See AGENTS.md for the full contributor + release workflow.
1717

1818
## Checklist
1919

20-
- [ ] `bash -n bin/*.sh install.sh bootstrap.sh` passes
21-
- [ ] `cargo build --release --manifest-path rs/Cargo.toml` passes (if any Rust changed)
20+
- [ ] Bash syntax + shellcheck pass through the `Lint` workflow
21+
- [ ] `cargo build --release --locked --manifest-path rs/Cargo.toml` passes (if any Rust changed)
2222
- [ ] `cargo fmt --manifest-path rs/Cargo.toml --check` passes (if any Rust changed)
23-
- [ ] `cargo clippy --release --manifest-path rs/Cargo.toml -- -D warnings` passes (if any Rust changed)
23+
- [ ] `cargo clippy --release --locked --manifest-path rs/Cargo.toml -- -D warnings` passes (if any Rust changed)
2424
- [ ] `flashpaste-doctor` runs clean against the changes
2525
- [ ] If this is a `vX.Y` bump: tag pushed in the same turn (see [AGENTS.md](../AGENTS.md))
2626
- [ ] `CHANGELOG.md` updated under `## [Unreleased]`

.github/workflows/lint.yml

Lines changed: 97 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,25 +31,116 @@ jobs:
3131
- name: bash -n syntax pre-check on every .sh
3232
run: |
3333
set -e
34-
# Recursively syntax-check every shell script in the repo.
34+
# Syntax-check every tracked shell script, including extensionless
35+
# helpers in bin/.
3536
# Fails fast so the more expensive shellcheck only runs if
3637
# the scripts parse at all.
3738
while IFS= read -r -d '' f; do
3839
echo "bash -n $f"
3940
bash -n "$f"
40-
done < <(find . -type f -name '*.sh' -not -path './rs/target/*' -print0)
41+
done < <(
42+
for f in $(git ls-files); do
43+
[ -f "$f" ] || continue
44+
case "$f" in
45+
*.sh) printf '%s\0' "$f" ;;
46+
*) head -n 1 "$f" | grep -Eq '^#!.*(ba)?sh' && printf '%s\0' "$f" || true ;;
47+
esac
48+
done
49+
)
4150
4251
- name: shellcheck (warning severity)
4352
run: |
4453
# SC1090 (can't follow non-constant source), SC2034 (unused var
4554
# exported for sibling scripts), SC2155 (declare and assign on
4655
# one line) are noisy in this codebase and intentional.
56+
mapfile -d '' shell_files < <(
57+
for f in $(git ls-files); do
58+
[ -f "$f" ] || continue
59+
case "$f" in
60+
*.sh) printf '%s\0' "$f" ;;
61+
*) head -n 1 "$f" | grep -Eq '^#!.*(ba)?sh' && printf '%s\0' "$f" || true ;;
62+
esac
63+
done
64+
)
4765
shellcheck -S warning \
4866
-e SC1090,SC2034,SC2155 \
49-
bin/*.sh \
50-
install.sh \
51-
bootstrap.sh \
52-
AGENTS-release-check.sh
67+
"${shell_files[@]}"
68+
69+
rust:
70+
name: rust fmt + clippy + unit tests
71+
runs-on: ubuntu-24.04
72+
steps:
73+
- uses: actions/checkout@v4
74+
75+
- name: Install Rust toolchain
76+
uses: dtolnay/rust-toolchain@stable
77+
with:
78+
components: rustfmt, clippy
79+
80+
- name: Install build dependencies
81+
run: |
82+
sudo apt-get update -qq
83+
sudo apt-get install -y libwayland-dev libx11-dev libdbus-1-dev pkg-config libcairo2-dev libglib2.0-dev libpango1.0-dev
84+
85+
- name: Cache cargo registry + target
86+
uses: actions/cache@v4
87+
with:
88+
path: |
89+
~/.cargo/registry
90+
~/.cargo/git
91+
rs/target
92+
key: ${{ runner.os }}-cargo-${{ hashFiles('rs/Cargo.lock', 'rs/Cargo.toml', 'rs/**/Cargo.toml') }}
93+
restore-keys: |
94+
${{ runner.os }}-cargo-
95+
96+
- name: cargo fmt
97+
run: cargo fmt --manifest-path rs/Cargo.toml --check
98+
99+
- name: cargo clippy
100+
run: cargo clippy --release --locked --manifest-path rs/Cargo.toml -- -D warnings
101+
102+
- name: cargo clippy overlay wayland
103+
run: cargo clippy --release --locked --manifest-path rs/Cargo.toml -p flashpaste-overlayd --features wayland -- -D warnings
104+
105+
- name: cargo unit tests
106+
run: cargo test --locked --manifest-path rs/Cargo.toml --workspace --lib --bins
107+
108+
package-smoke:
109+
name: package smoke
110+
runs-on: ubuntu-24.04
111+
steps:
112+
- uses: actions/checkout@v4
113+
114+
- name: Install Rust toolchain
115+
uses: dtolnay/rust-toolchain@stable
116+
117+
- name: Install package build dependencies
118+
run: |
119+
sudo apt-get update -qq
120+
sudo apt-get install -y dpkg-dev libwayland-dev libx11-dev libdbus-1-dev pkg-config libcairo2-dev libglib2.0-dev libpango1.0-dev
121+
122+
- name: Cache cargo registry + target
123+
uses: actions/cache@v4
124+
with:
125+
path: |
126+
~/.cargo/registry
127+
~/.cargo/git
128+
rs/target
129+
key: ${{ runner.os }}-cargo-${{ hashFiles('rs/Cargo.lock', 'rs/Cargo.toml', 'rs/**/Cargo.toml') }}
130+
restore-keys: |
131+
${{ runner.os }}-cargo-
132+
133+
- name: Build Rust workspace
134+
run: cargo build --release --locked --manifest-path rs/Cargo.toml
135+
136+
- name: Build overlay daemon
137+
run: cargo build --release --locked --manifest-path rs/Cargo.toml -p flashpaste-overlayd --features wayland
138+
139+
- name: Build .deb
140+
run: VERSION=0.0.0 bash packaging/build-deb.sh
141+
142+
- name: Install package in Ubuntu container
143+
run: bash packaging/package-smoke.sh
53144

54145
markdown-lint:
55146
name: markdownlint

.github/workflows/release.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,22 @@ jobs:
3939
~/.cargo/registry
4040
~/.cargo/git
4141
rs/target
42-
key: ${{ runner.os }}-cargo-${{ hashFiles('rs/Cargo.toml', 'rs/**/Cargo.toml') }}
42+
key: ${{ runner.os }}-cargo-${{ hashFiles('rs/Cargo.lock', 'rs/Cargo.toml', 'rs/**/Cargo.toml') }}
4343
restore-keys: |
4444
${{ runner.os }}-cargo-
4545
4646
- name: Build Rust workspace
47-
run: cargo build --release --manifest-path rs/Cargo.toml
47+
run: cargo build --release --locked --manifest-path rs/Cargo.toml
4848

4949
- name: Build overlay daemon
50-
run: cargo build --release --manifest-path rs/Cargo.toml -p flashpaste-overlayd --features wayland
50+
run: cargo build --release --locked --manifest-path rs/Cargo.toml -p flashpaste-overlayd --features wayland
5151

5252
- name: Build .deb
5353
run: VERSION=${{ steps.ver.outputs.v }} bash packaging/build-deb.sh
5454

55+
- name: Package smoke test
56+
run: bash packaging/package-smoke.sh
57+
5558
- name: Show package info
5659
run: |
5760
ls -la dist/
@@ -64,5 +67,6 @@ jobs:
6467
run: |
6568
gh release create "${GITHUB_REF_NAME}" \
6669
dist/flashpaste_${{ steps.ver.outputs.v }}_all.deb \
70+
dist/flashpaste_all.deb \
6771
--title "flashpaste ${GITHUB_REF_NAME}" \
6872
--generate-notes

AGENTS-release-check.sh

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,35 @@ git fetch origin --tags --quiet 2>/dev/null || true
2626
missing_tags=0
2727
missing_releases=0
2828

29+
historical_exception() {
30+
local tag="$1" sha="$2"
31+
# v1.10-v1.14 predate the release workflow and are explicitly documented in
32+
# AGENTS.md as no-backfill-by-default history.
33+
case "$tag" in
34+
v1.10|v1.11|v1.12|v1.13|v1.14)
35+
return 0
36+
;;
37+
esac
38+
# Early post-policy history contains duplicate version subjects. The tag for
39+
# each version points at the canonical release commit; these older subjects
40+
# are preserved in git history but must not keep every future audit red.
41+
case "$tag:$sha" in
42+
v1.18:378a91620eb690ccf9469dbf4e24c55f0a637fba|\
43+
v1.20:02aaed161dddc3536f655dcfb65707b7b5613139|\
44+
v1.21:72c4845f962221feb1ddf7719279b478f65cb170)
45+
return 0
46+
;;
47+
esac
48+
return 1
49+
}
50+
2951
# Walk every commit whose subject starts with `vX.Y[.Z]:`.
3052
while IFS=$'\t' read -r sha subject; do
3153
tag=$(printf '%s' "$subject" | awk '{print $1}' | tr -d ':')
54+
if historical_exception "$tag" "$sha"; then
55+
[ "$VERBOSE" = "1" ] && printf 'SKIP %s %s historical exception\n' "$tag" "$sha"
56+
continue
57+
fi
3258
# The tag must (a) exist locally and (b) point at this same commit.
3359
if ! git rev-parse --verify --quiet "refs/tags/$tag" >/dev/null; then
3460
printf 'MISSING TAG %s %s\n' "$tag" "$sha"

Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ uninstall:
4646
@for f in tmux-paste-dispatch.sh clipboard-set.sh clipboard-janitor.sh \
4747
get-clipboard-text.sh clip-pipeline-log.sh screenshot-to-clipboard \
4848
flashpaste-screenshot-preload.sh flashpaste-doctor.sh \
49-
flashpaste-trace.sh wl-paste flashpaste-overlayd flashpaste-overlay; do \
49+
flashpaste-trace.sh wl-paste tmux-paste-dispatch flashpaste-overlayd flashpaste-overlay; do \
5050
[ -L "$$HOME/.local/bin/$$f" ] && rm "$$HOME/.local/bin/$$f" && echo " removed ~/.local/bin/$$f" || true; \
5151
done
5252
@for f in wl-clipboard.desktop wl-paste.desktop wl-copy.desktop; do \
@@ -61,8 +61,9 @@ clean:
6161

6262
release-deb: deb
6363
@echo "release-deb produced: dist/flashpaste_$(VERSION)_all.deb"
64+
@echo "stable alias produced: dist/flashpaste_all.deb"
6465
@echo "Upload to GitHub Releases:"
65-
@echo " gh release create v$(VERSION) dist/flashpaste_$(VERSION)_all.deb --title 'flashpaste v$(VERSION)' --generate-notes"
66+
@echo " gh release create v$(VERSION) dist/flashpaste_$(VERSION)_all.deb dist/flashpaste_all.deb --title 'flashpaste v$(VERSION)' --generate-notes"
6667

6768
# ---------------------------------------------------------------------------
6869
# Benchmarks

bin/clipboard-janitor.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ exec 9>"$LOCK" || exit 0
4949
flock -n 9 || exit 0
5050
trap 'rm -f "$LOCK" 2>/dev/null' EXIT
5151

52-
. /home/deadpool/.local/bin/clip-pipeline-log.sh 2>/dev/null || true
52+
_self_dir=$(dirname -- "$0")
53+
_clog_helper=$(command -v clip-pipeline-log.sh 2>/dev/null || true)
54+
[ -n "$_clog_helper" ] || _clog_helper="$_self_dir/clip-pipeline-log.sh"
55+
. "$_clog_helper" 2>/dev/null || true
5356
type clog >/dev/null 2>&1 || clog() { :; }
5457
log() {
5558
printf '[clipboard-janitor] %s\n' "$*" >&2

bin/clipboard-set.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
set -u
1919

2020
# Pipeline logging.
21-
. /home/deadpool/.local/bin/clip-pipeline-log.sh 2>/dev/null || true
21+
_self_dir=$(dirname -- "$0")
22+
_clog_helper=$(command -v clip-pipeline-log.sh 2>/dev/null || true)
23+
[ -n "$_clog_helper" ] || _clog_helper="$_self_dir/clip-pipeline-log.sh"
24+
. "$_clog_helper" 2>/dev/null || true
2225
type clog >/dev/null 2>&1 || clog() { :; }
2326
type clog_preview >/dev/null 2>&1 || clog_preview() { printf '%s' "${1:-}"; }
2427

bin/flashpaste-doctor.sh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,10 @@ emit() {
171171
fi
172172
) &
173173

174-
# 11. tmux-paste-dispatch.sh already installed?
175-
( if [ -x "$HOME/.local/bin/tmux-paste-dispatch.sh" ]; then
174+
# 11. tmux-paste-dispatch already installed?
175+
( if path=$(command -v tmux-paste-dispatch 2>/dev/null || command -v tmux-paste-dispatch.sh 2>/dev/null); then
176+
emit ok "flashpaste installed" "$path" 110
177+
elif [ -x "$HOME/.local/bin/tmux-paste-dispatch.sh" ]; then
176178
emit ok "flashpaste installed" "$HOME/.local/bin/tmux-paste-dispatch.sh" 110
177179
else
178180
emit warn "flashpaste installed" "not yet — bootstrap.sh / install.sh will fix this" 110

bin/get-clipboard-text.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@
2828
# branch's output is funneled through `is_text` before being accepted.
2929
set -u
3030

31-
. /home/deadpool/.local/bin/clip-pipeline-log.sh 2>/dev/null || true
31+
_self_dir=$(dirname -- "$0")
32+
_clog_helper=$(command -v clip-pipeline-log.sh 2>/dev/null || true)
33+
[ -n "$_clog_helper" ] || _clog_helper="$_self_dir/clip-pipeline-log.sh"
34+
. "$_clog_helper" 2>/dev/null || true
3235
type clog >/dev/null 2>&1 || clog() { :; }
3336
clog "get-clipboard" "event=invoked"
3437

bin/paste_image.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@
3535
# "text" → force text branch
3636
set -u
3737

38-
. /home/deadpool/.local/bin/clip-pipeline-log.sh 2>/dev/null || true
38+
_self_dir=$(dirname -- "$0")
39+
_clog_helper=$(command -v clip-pipeline-log.sh 2>/dev/null || true)
40+
[ -n "$_clog_helper" ] || _clog_helper="$_self_dir/clip-pipeline-log.sh"
41+
. "$_clog_helper" 2>/dev/null || true
3942
type clog >/dev/null 2>&1 || clog() { :; }
4043
clog "paste-image" "event=invoked" "arg='${1:-}'" "KITTY_WINDOW_ID='${KITTY_WINDOW_ID:-}'" "KITTY_LISTEN_ON='${KITTY_LISTEN_ON:-}'"
4144

0 commit comments

Comments
 (0)