Skip to content

Commit 54cd38f

Browse files
authored
Merge branch 'main' into fix/pane-centric-migration-cleanup
2 parents 0293e47 + 77be417 commit 54cd38f

7 files changed

Lines changed: 615 additions & 3 deletions

File tree

.github/workflows/ci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ on:
1010
- 'resources/**'
1111
- 'deps.edn'
1212
- 'build.clj'
13+
- 'install.sh'
14+
- 'README.md'
15+
- 'README.ja.md'
1316
- '.clj-kondo/**'
1417
- '.github/workflows/ci.yml'
1518
- 'renovate.json5'
@@ -22,6 +25,9 @@ on:
2225
- 'resources/**'
2326
- 'deps.edn'
2427
- 'build.clj'
28+
- 'install.sh'
29+
- 'README.md'
30+
- 'README.ja.md'
2531
- '.clj-kondo/**'
2632
- '.github/workflows/ci.yml'
2733
- 'renovate.json5'

Makefile

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
.PHONY: test lint format-check format ci run clean uber
1+
.PHONY: test test-install-script lint format-check format ci run clean uber
22

3-
test:
4-
clojure -M:test
3+
test: test-install-script
4+
mkdir -p target/test-runtime
5+
XDG_RUNTIME_DIR=$(CURDIR)/target/test-runtime clojure -M:test
6+
7+
test-install-script:
8+
sh test/install_script_test.sh
59

610
lint:
711
clojure -M:lint

README.ja.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,30 @@ tmuxペインを横断してAIコーディングエージェントのセッシ
2121

2222
## インストール
2323

24+
### ワンライナーインストール
25+
26+
```bash
27+
curl -fsSL https://raw.githubusercontent.com/boxp/ceeker/main/install.sh | sh
28+
```
29+
30+
対応プラットフォーム: `darwin-arm64`, `linux-amd64`, `linux-arm64`
31+
32+
このインストーラは GitHub Releases から対応 tarball を取得し、`checksums.txt` で検証したうえで、既定では `~/.local/bin``ceeker` を配置します。
33+
34+
配置先を変える例:
35+
36+
```bash
37+
curl -fsSL https://raw.githubusercontent.com/boxp/ceeker/main/install.sh | sh -s -- -b ~/.local/bin
38+
```
39+
40+
特定バージョンを入れる例:
41+
42+
```bash
43+
curl -fsSL https://raw.githubusercontent.com/boxp/ceeker/main/install.sh | sh -s -- -v 0.1.0
44+
```
45+
46+
未対応プラットフォームでは、以下の Homebrew または tarball 手順を使ってください。
47+
2448
### Homebrew(macOS / Linux)
2549

2650
```bash

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,30 @@ In environments where multiple AI coding agents (Claude Code / Codex) run in par
2121

2222
## Installation
2323

24+
### One-liner install
25+
26+
```bash
27+
curl -fsSL https://raw.githubusercontent.com/boxp/ceeker/main/install.sh | sh
28+
```
29+
30+
Supported platforms: `darwin-arm64`, `linux-amd64`, `linux-arm64`
31+
32+
This installer downloads the matching release tarball from GitHub Releases, verifies it against `checksums.txt`, and installs `ceeker` to `~/.local/bin` by default.
33+
34+
Custom install directory:
35+
36+
```bash
37+
curl -fsSL https://raw.githubusercontent.com/boxp/ceeker/main/install.sh | sh -s -- -b ~/.local/bin
38+
```
39+
40+
Install a specific version:
41+
42+
```bash
43+
curl -fsSL https://raw.githubusercontent.com/boxp/ceeker/main/install.sh | sh -s -- -v 0.1.0
44+
```
45+
46+
Unsupported platforms should use Homebrew or the manual tarball installation below.
47+
2448
### Homebrew (macOS / Linux)
2549

2650
```bash
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# ceeker ワンライナー導入計画
2+
3+
## Summary
4+
5+
GitHub Releases の既存ネイティブ tarball を使う `install.sh` をリポジトリ直下に追加し、`curl -fsSL ... | sh` だけで `ceeker` を導入できる状態にする。
6+
既定の配置先は `~/.local/bin`、対応プラットフォームは現行 Release と一致する `darwin-arm64` / `linux-amd64` / `linux-arm64` に限定し、未対応環境は明示エラーにする。
7+
実装開始時の最初の変更として、今回の計画を `docs/project_docs/ceeker-install-script/plan.md` に保存し、同じ PR に含める。
8+
9+
## Key Changes
10+
11+
- `install.sh` を追加する
12+
- POSIX `sh` ベースで実装する
13+
- 既定動作は latest 版を `${HOME}/.local/bin/ceeker` にインストールする
14+
- `-b` / `--bin-dir``-v` / `--version` を受け付ける
15+
- 環境変数 `BIN_DIR` / `VERSION` でも上書き可能にし、優先順位は `CLI引数 > 環境変数 > デフォルト` に固定する
16+
- `uname -s` / `uname -m` から `darwin-arm64` / `linux-amd64` / `linux-arm64` に正規化する
17+
- ダウンロード URL は以下に固定する
18+
- latest: `https://github.com/boxp/ceeker/releases/latest/download/ceeker-${platform}.tar.gz`
19+
- 明示版: `https://github.com/boxp/ceeker/releases/download/v${VERSION}/ceeker-${platform}.tar.gz`
20+
- 同じ release から `checksums.txt` も取得し、tarball の SHA256 を検証してから展開する
21+
- 検証コマンドは `sha256sum` を優先し、未導入環境では `shasum -a 256` にフォールバックする
22+
- `curl``tar``sha256sum` または `shasum` のいずれかの存在確認を行い、足りなければ即時エラーにする
23+
- 一時ディレクトリへ展開し、展開された単一バイナリを `ceeker` にリネームして配置する
24+
- 配置先ディレクトリがなければ作成する
25+
- インストール後に `ceeker --version` を実行して成功確認する
26+
- `PATH` に配置先が含まれない場合は、その旨を案内する
27+
- 未対応 OS/arch、ダウンロード失敗、チェックサム不一致、展開失敗時は non-zero exit で理由を表示する
28+
29+
- 配布物の整合性ポリシーを固定する
30+
- README の推奨ワンライナーは `main` 上の `install.sh` を取得する
31+
- その代わり `install.sh` は release asset のファイル名規約と `checksums.txt` のみを契約面とし、latest / `vX.Y.Z` の両方で動く後方互換を維持する
32+
- installer 固有の release asset は追加しない
33+
- この方針を README に短く明記し、インストーラ変更時は既存 release 命名規約を壊さない前提で運用する
34+
35+
- README を英日両方更新する
36+
- `README.md``README.ja.md` に「One-liner install」節を追加する
37+
- 推奨ワンライナーは `curl -fsSL https://raw.githubusercontent.com/boxp/ceeker/main/install.sh | sh`
38+
- カスタム配置先とバージョン固定の例も載せる
39+
- `curl ... | sh -s -- -b ~/.local/bin`
40+
- `curl ... | sh -s -- -v 0.1.0`
41+
- サポート対象を明記し、非対応環境は Homebrew または手動導入へ誘導する
42+
- 既存の Homebrew / tarball 手順は残し、ワンライナーを最短導線として先頭に置く
43+
44+
- TDD と CI 導線を明確化する
45+
- まず失敗するテストを追加し、その後に `install.sh` を実装する
46+
- スクリプトテストは新規 `test/install_script_test.sh` に切り出し、POSIX `sh` で実行できる自前テストにする
47+
- テストでは `curl` / `tar` / `uname` / `mktemp` / `ceeker --version` / ハッシュ計算コマンドをモックできるよう、`install.sh` を外部コマンド呼び出し境界ごとに差し替え可能な構成にする
48+
- `Makefile``test-install-script` を追加し、`test` ターゲットから Clojure テストの前後どちらかで必ず実行する
49+
- `ci` は既存どおり `format-check lint test` を維持し、`test` に shell テストが含まれる状態にする
50+
- `.github/workflows/ci.yml` の path filter に `README.md``README.ja.md``install.sh``test/install_script_test.sh` を追加し、この変更が PR で必ず CI 実行対象になるようにする
51+
52+
## Public Interfaces
53+
54+
- 新規公開ファイル: `install.sh`
55+
- 新規 Make ターゲット: `test-install-script`
56+
- 利用者向けインターフェース
57+
- `sh install.sh`
58+
- `sh install.sh -b <dir>`
59+
- `sh install.sh -v <version>`
60+
- `BIN_DIR=<dir> VERSION=<version> sh install.sh`
61+
- README に公開するワンライナー
62+
- `curl -fsSL https://raw.githubusercontent.com/boxp/ceeker/main/install.sh | sh`
63+
64+
## Test Plan
65+
66+
- `test/install_script_test.sh` で以下を固定する
67+
- `linux-amd64` / `linux-arm64` / `darwin-arm64` の判定
68+
- 未対応環境での失敗
69+
- latest URL と固定バージョン URL の切り替え
70+
- `-b` / `-v``BIN_DIR` / `VERSION` の優先順位
71+
- `checksums.txt` の取得と SHA256 検証成功
72+
- チェックサム不一致時の失敗
73+
- 配置先ディレクトリ作成
74+
- `PATH` 未設定時の案内
75+
- `ceeker --version` 成功で正常終了すること
76+
- `make ci` を実行し、既存 Clojure 側の format/lint/test と追加 shell テストが通ることを確認する
77+
- 追加で一時ディレクトリ向けのスモーク実行を行い、実際に配置された `ceeker --version` まで通ることを確認する
78+
79+
## Assumptions
80+
81+
- 配布元は既存 GitHub Releases を使い、新しい配布基盤は追加しない
82+
- macOS Intel は今回の対象外とし、Release/CI 拡張は別タスクに分離する
83+
- `install.sh` はリポジトリ直下に置き、`raw.githubusercontent.com` から取得する
84+
- 既定配置先は `~/.local/bin` を採用する
85+
- `main` 上の installer は、公開済み release の tarball 命名規約と `checksums.txt` に対して後方互換を維持する

install.sh

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
#!/usr/bin/env sh
2+
set -eu
3+
4+
REPO_OWNER="boxp"
5+
REPO_NAME="ceeker"
6+
DEFAULT_BIN_DIR="${HOME}/.local/bin"
7+
8+
usage() {
9+
cat <<'EOF'
10+
Usage: install.sh [-b BIN_DIR] [-v VERSION]
11+
12+
Options:
13+
-b, --bin-dir Installation directory (default: ~/.local/bin)
14+
-v, --version Release version without leading v (default: latest)
15+
-h, --help Show this help
16+
EOF
17+
}
18+
19+
fail() {
20+
printf '%s\n' "$1" >&2
21+
exit 1
22+
}
23+
24+
require_command() {
25+
command -v "$1" >/dev/null 2>&1 || fail "Required command not found: $1"
26+
}
27+
28+
normalize_version() {
29+
case "$1" in
30+
"" | latest)
31+
printf 'latest\n'
32+
;;
33+
v*)
34+
printf '%s\n' "${1#v}"
35+
;;
36+
*)
37+
printf '%s\n' "$1"
38+
;;
39+
esac
40+
}
41+
42+
detect_platform() {
43+
os_name=$(uname -s)
44+
arch_name=$(uname -m)
45+
46+
case "${os_name}" in
47+
Linux)
48+
case "${arch_name}" in
49+
x86_64 | amd64)
50+
printf 'linux-amd64\n'
51+
return 0
52+
;;
53+
aarch64 | arm64)
54+
printf 'linux-arm64\n'
55+
return 0
56+
;;
57+
esac
58+
;;
59+
Darwin)
60+
case "${arch_name}" in
61+
arm64 | aarch64)
62+
printf 'darwin-arm64\n'
63+
return 0
64+
;;
65+
esac
66+
;;
67+
esac
68+
69+
fail "Unsupported platform: ${os_name} ${arch_name}"
70+
}
71+
72+
download_url() {
73+
platform="$1"
74+
version="$2"
75+
76+
if [ "${version}" = "latest" ]; then
77+
printf 'https://github.com/%s/%s/releases/latest/download/ceeker-%s.tar.gz\n' "${REPO_OWNER}" "${REPO_NAME}" "${platform}"
78+
return 0
79+
fi
80+
81+
printf 'https://github.com/%s/%s/releases/download/v%s/ceeker-%s.tar.gz\n' "${REPO_OWNER}" "${REPO_NAME}" "${version}" "${platform}"
82+
}
83+
84+
checksum_url() {
85+
version="$1"
86+
87+
if [ "${version}" = "latest" ]; then
88+
printf 'https://github.com/%s/%s/releases/latest/download/checksums.txt\n' "${REPO_OWNER}" "${REPO_NAME}"
89+
return 0
90+
fi
91+
92+
printf 'https://github.com/%s/%s/releases/download/v%s/checksums.txt\n' "${REPO_OWNER}" "${REPO_NAME}" "${version}"
93+
}
94+
95+
hash_file() {
96+
file_path="$1"
97+
98+
if command -v sha256sum >/dev/null 2>&1; then
99+
sha256sum "${file_path}" | awk '{print $1}'
100+
return 0
101+
fi
102+
103+
if command -v shasum >/dev/null 2>&1; then
104+
shasum -a 256 "${file_path}" | awk '{print $1}'
105+
return 0
106+
fi
107+
108+
fail "Required command not found: sha256sum or shasum"
109+
}
110+
111+
expected_checksum() {
112+
checksums_file="$1"
113+
tarball_name="$2"
114+
checksum=$(awk -v target="${tarball_name}" '$2 == target { print $1 }' "${checksums_file}")
115+
[ -n "${checksum}" ] || fail "Checksum entry not found for ${tarball_name}"
116+
printf '%s\n' "${checksum}"
117+
}
118+
119+
bin_dir="${BIN_DIR:-${DEFAULT_BIN_DIR}}"
120+
version="$(normalize_version "${VERSION:-latest}")"
121+
122+
while [ "$#" -gt 0 ]; do
123+
case "$1" in
124+
-b | --bin-dir)
125+
[ "$#" -ge 2 ] || fail "Missing value for $1"
126+
bin_dir="$2"
127+
shift 2
128+
;;
129+
-v | --version)
130+
[ "$#" -ge 2 ] || fail "Missing value for $1"
131+
version="$(normalize_version "$2")"
132+
shift 2
133+
;;
134+
-h | --help)
135+
usage
136+
exit 0
137+
;;
138+
*)
139+
fail "Unknown option: $1"
140+
;;
141+
esac
142+
done
143+
144+
require_command curl
145+
require_command tar
146+
if ! command -v sha256sum >/dev/null 2>&1 && ! command -v shasum >/dev/null 2>&1; then
147+
fail "Required command not found: sha256sum or shasum"
148+
fi
149+
150+
platform="$(detect_platform)"
151+
tarball_name="ceeker-${platform}.tar.gz"
152+
tmp_dir="$(mktemp -d)"
153+
tarball_path="${tmp_dir}/${tarball_name}"
154+
checksums_path="${tmp_dir}/checksums.txt"
155+
binary_path="${tmp_dir}/ceeker-${platform}"
156+
install_path="${bin_dir}/ceeker"
157+
158+
cleanup() {
159+
rm -rf "${tmp_dir}"
160+
}
161+
162+
trap cleanup EXIT HUP INT TERM
163+
164+
curl -fsSL "$(download_url "${platform}" "${version}")" -o "${tarball_path}"
165+
curl -fsSL "$(checksum_url "${version}")" -o "${checksums_path}"
166+
167+
expected="$(expected_checksum "${checksums_path}" "${tarball_name}")"
168+
actual="$(hash_file "${tarball_path}")"
169+
[ "${expected}" = "${actual}" ] || fail "Checksum mismatch for ${tarball_name}"
170+
171+
mkdir -p "${bin_dir}"
172+
tar -xzf "${tarball_path}" -C "${tmp_dir}"
173+
[ -f "${binary_path}" ] || fail "Extracted binary not found: ceeker-${platform}"
174+
chmod +x "${binary_path}"
175+
mv "${binary_path}" "${install_path}"
176+
177+
"${install_path}" --version >/dev/null 2>&1 || fail "Installed binary failed validation: ${install_path}"
178+
179+
printf 'Installed ceeker to %s\n' "${install_path}"
180+
case ":${PATH:-}:" in
181+
*:"${bin_dir}":*)
182+
;;
183+
*)
184+
printf 'Add %s to PATH\n' "${bin_dir}"
185+
;;
186+
esac

0 commit comments

Comments
 (0)