Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,59 @@ jobs:
- name: Build packages
run: go build ./...

- name: Initialize Homebrew tap repository
env:
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
run: |
set -euo pipefail

curl_status_args=(
-sS
--connect-timeout 10
--max-time 20
--retry 3
--retry-delay 2
--retry-all-errors
-o /dev/null
-w '%{http_code}'
-H 'Accept: application/vnd.github+json'
-H "Authorization: Bearer ${HOMEBREW_TAP_GITHUB_TOKEN}"
)

tap_repo_api_url="https://api.github.com/repos/harumiWeb/homebrew-eitango"
repo_status_code="$(curl "${curl_status_args[@]}" "${tap_repo_api_url}")"

if [ "${repo_status_code}" != "200" ]; then
echo "homebrew tap repository is missing or inaccessible: ${repo_status_code}" >&2
exit 1
fi

tap_branch_api_url="https://api.github.com/repos/harumiWeb/homebrew-eitango/git/ref/heads/main"
branch_status_code="$(curl "${curl_status_args[@]}" "${tap_branch_api_url}")"

if [ "${branch_status_code}" = "200" ]; then
exit 0
fi

if [ "${branch_status_code}" != "404" ] && [ "${branch_status_code}" != "409" ]; then
echo "unexpected tap branch status: ${branch_status_code}" >&2
exit 1
fi

tmpdir="$(mktemp -d)"
trap 'rm -rf "${tmpdir}"' EXIT

git -C "${tmpdir}" init -b main
cat <<'EOF' > "${tmpdir}/README.md"
# homebrew-eitango

Homebrew tap for eitango release formulas.
EOF
git -C "${tmpdir}" add README.md
git -C "${tmpdir}" -c user.name='github-actions[bot]' -c user.email='41898282+github-actions[bot]@users.noreply.github.com' commit -m 'Initialize tap repository'
git -C "${tmpdir}" remote add origin "https://x-access-token:${HOMEBREW_TAP_GITHUB_TOKEN}@github.com/harumiWeb/homebrew-eitango.git"
git -C "${tmpdir}" push origin main

- name: Publish release artifacts
uses: goreleaser/goreleaser-action@v6
with:
Expand All @@ -41,4 +94,5 @@ jobs:
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
WINGET_GITHUB_TOKEN: ${{ secrets.WINGET_GITHUB_TOKEN }}
26 changes: 26 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,32 @@ archives:
- goos: linux
formats: [none]

brews:
- name: eitango
ids:
- unix-archives
directory: Formula
homepage: https://github.com/harumiWeb/eitango
description: Interactive English vocabulary learning CLI built with Go.
license: Apache-2.0
commit_msg_template: "Brew formula update for {{ .ProjectName }} version {{ .Tag }}"
repository:
owner: harumiWeb
name: homebrew-eitango
branch: main
token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
commit_author:
name: github-actions[bot]
email: 41898282+github-actions[bot]@users.noreply.github.com
install: |
bin.install "eitango"
doc.install "README.md", "README.en.md"
pkgshare.install "LICENSE", "THIRD_PARTY_NOTICES.md"
(pkgshare/"third_party").install "third_party/licenses"
test: |
system "#{bin}/eitango", "--help"
skip_upload: "{{ if .Prerelease }}true{{ else }}false{{ end }}"

winget:
- name: eitango
publisher: HarumiWeb
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@

## [Unreleased]

## [0.7.1] - 2026-04-11

### Added

- release パイプラインが Homebrew tap `harumiWeb/homebrew-eitango` へ formula を publish できるようになり、macOS / Linux で `brew` install 導線を提供できるようにしました。

## [0.7.0] - 2026-04-11

### Added
Expand Down
21 changes: 18 additions & 3 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,22 @@ winget upgrade HarumiWeb.Eitango

If you do not want to use winget, you can still use the GitHub Releases zip described below.

### 2. Use `curl | sh` on macOS / Linux
### 2. Use Homebrew on macOS / Linux

On macOS / Linux, you can also install `eitango` from the Homebrew tap. The formula points to the darwin / linux `tar.gz` archives published in GitHub Releases.

```bash
brew tap harumiWeb/eitango
brew install eitango
```

To upgrade:

```bash
brew upgrade eitango
```

### 3. Use `curl | sh` on macOS / Linux

`install.sh` calls the GitHub Releases API (`/releases/latest`) when `--version` is omitted to resolve the latest version, then downloads the matching GitHub Release archive and `checksums.txt`. It installs into `~/.eitango/` only after the SHA256 check passes, and it never edits shell rc files automatically.

Expand Down Expand Up @@ -126,13 +141,13 @@ curl -fsSL https://raw.githubusercontent.com/harumiWeb/eitango/main/install.sh |

Required tools are `sh`, `curl`, `tar`, `mktemp`, and one of `sha256sum`, `shasum`, or `openssl`. Windows is out of scope for this installer, so use winget or the release zip there.

### 3. Use GitHub Releases
### 4. Use GitHub Releases

Published archives include the executable plus `LICENSE`, `THIRD_PARTY_NOTICES.md`, and `third_party/licenses/`. Extract the artifact for your OS and run `eitango`.

※ You need to manually add it to your `PATH`.

### 4. Install with Go
### 5. Install with Go

Go 1.26 or newer is required.

Expand Down
21 changes: 18 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,22 @@ winget を使わない場合は後述の GitHub Releases の zip からも利用
> [!NOTE]
> winget は 都合上、他の配布手段よりリリースからの反映が遅れる可能性があります。最新 release をすぐに使いたい場合は、次のいずれかを選択してください。

### 2. macOS / Linux は `curl | sh` を使う
### 2. macOS / Linux は Homebrew を使う

macOS / Linux では Homebrew tap からも install できます。formula は GitHub Releases に公開した darwin / linux の `tar.gz` を参照します。

```bash
brew tap harumiWeb/eitango
brew install eitango
```

更新は次です。

```bash
brew upgrade eitango
```

### 3. macOS / Linux は `curl | sh` を使う

`install.sh` は `--version` を省略した場合に GitHub Releases API (`/releases/latest`) へアクセスして最新 version を解決し、そのうえで対応する archive と `checksums.txt` を取得します。SHA256 検証が通ったときだけ `~/.eitango/` へ展開し、shell rc は自動変更しません。

Expand Down Expand Up @@ -129,13 +144,13 @@ curl -fsSL https://raw.githubusercontent.com/harumiWeb/eitango/main/install.sh |

必要ツールは `sh`, `curl`, `tar`, `mktemp` と、`sha256sum` / `shasum` / `openssl` のいずれか 1 つです。Windows は今回の installer 対象外なので、winget か release zip を使ってください。

### 3. GitHub Releases から使う
### 4. GitHub Releases から使う

公開アーカイブにはバイナリに加えて `LICENSE`、`THIRD_PARTY_NOTICES.md`、`third_party/licenses/` が同梱されます。自分のOS向けの成果物を展開して `eitango` を実行してください。

※ `PATH`への追加は手動で行う必要があります。

### 4. Go からインストールする
### 5. Go からインストールする

Go 1.26 以降を前提にしています。

Expand Down
9 changes: 7 additions & 2 deletions docs/adr/0003-release-and-update-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
## Decision

- 正規の配布チャネルは GitHub Releases とし、GoReleaser で darwin / linux / windows 向け archive を生成する。
- macOS / linux 向けには Homebrew tap `harumiWeb/homebrew-eitango` も配布導線として提供するが、formula の参照先 artifact は GitHub Releases に置いた darwin / linux `tar.gz` のみとし、release の正本は引き続き GitHub Releases に固定する。
- Windows 向けには winget community repository も配布導線として提供するが、参照先 artifact は GitHub Releases に置いた Windows zip のみとし、release の正本は引き続き GitHub Releases に固定する。
- release artifact には実行バイナリに加えて `LICENSE`, `README.md`, `README.en.md`, `THIRD_PARTY_NOTICES.md`, `third_party/licenses/**` を同梱する。
- macOS / linux では `install.sh` を bootstrap 導線として許可するが、installer 自体は GitHub Releases の archive と `checksums.txt` を取得する薄い wrapper に留める。
- `install.sh` は `checksums.txt` で SHA256 を必須検証し、法務ファイルを `~/.eitango/share/` へ保持する。
- Homebrew formula は GoReleaser で release 時に生成し、`harumiWeb/homebrew-eitango` へ push する。push 用 token は release 用 `GITHUB_TOKEN` と分離した `HOMEBREW_TAP_GITHUB_TOKEN` を使い、prerelease tag は tap へ publish しない。
- winget manifest は GoReleaser で release 時に生成し、`harumiWeb/winget-pkgs` fork へ push する。`microsoft/winget-pkgs` への PR は手動で作成し、fork への push 用 token は release 用 `GITHUB_TOKEN` と分離した `WINGET_GITHUB_TOKEN` を使う。
- 更新は自動適用しない。新しい版の取得は release archive の再取得か `go install ...@latest` の再実行で行う。
- update check は GitHub Releases の latest を参照する補助機能とし、学習フローを止めない best-effort 動作に限定する。
Expand All @@ -27,14 +29,15 @@
## Consequences

- release artifact の再配布条件と notice の同梱要件を、ビルド設定と文書で一貫して維持できる。
- macOS / Linux 利用者には `brew tap harumiWeb/eitango && brew install eitango` の導線を追加できるが、artifact hosting と checksum の正本は増やさずに済む。
- Windows 利用者には `winget install HarumiWeb.Eitango` の導線を追加できるが、artifact hosting と checksum の正本は増やさずに済む。
- `curl | sh` の最短導線を追加しても、配布物の単一ソースは GitHub Releases のまま保てる。
- SHA256 検証で download 途中の破損や取り違えは防ぎやすくなるが、署名付き provenance ではないため `install.sh` 本体の信頼境界は依然として HTTPS / GitHub 側にある。
- 自動更新を持たないため、更新失敗が学習データを壊す経路を増やさずに済む。
- update check は起動ごとに 1 回の best-effort request を行うが、最新 release 反映の遅延は大きく減り、更新作業は引き続き手動のまま保てる。
- 保存済み state があるため、GitHub API が失敗しても直前の latest 情報を fallback として使える。
- fork 側 PAT の期限切れや権限不足があると winget manifest push が失敗しうるため、release 失敗時は token 権限と fork 状態を先に確認する運用が必要になる。upstream PR は手動運用なので、release 後に compare URL から提出する手順を別途維持する必要がある。
- GitHub Releases が update metadata と Windows zip の単一ソースになるため、別チャネルを増やす場合は新しい判断が必要になる
- tap / fork 側 PAT の期限切れや権限不足があると Homebrew formula push や winget manifest push が失敗しうるため、release 失敗時は token 権限と publish 先 repository 状態を先に確認する運用が必要になる。upstream PR は手動運用なので、release 後に compare URL から提出する手順を別途維持する必要がある。
- GitHub Releases が update metadata と Homebrew / winget の参照先 artifact の単一ソースになるため、さらに別チャネルを増やす場合は新しい判断が必要になる

## Rationale

Expand All @@ -48,6 +51,8 @@
- `.goreleaser.yaml`
- `.github/workflows/release.yml`
- `install.sh`
- `README.md`
- `README.en.md`
- Related specs:
- なし。コード、README、CHANGELOG、tests を正本とする。

Expand Down
1 change: 1 addition & 0 deletions tasks/lessons.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
- 非同期エラーを UI 用 message へ潰すときも root cause を落とさない。`audioErrMsg` のような軽量 message でも trigger source と元 error を保持し、status は短く保ったまま診断と回帰テストに使える形で残す。
- 外部コマンド実行を security lint が見ている箇所は、validated な入力でも `exec.CommandContext(name, ...)` の形を避ける。`LookPath` は存在確認と allowlist 判定に使い、実行は静的 literal のコマンドに正規化して Semgrep/Codacy と実装意図を一致させる。
- `winget-pkgs` のような fork 経由の upstream PR を自動化する前に、PAT の owner 境界を確認する。fine-grained PAT は選択した owner 配下の repo にしか権限を持てないので、fork への push はできても別 owner への cross-repository PR 作成は失敗しうる。
- cross-repository publish の初期化 step で `git/ref/heads/...` の 404 を branch 不在と決め打ちしない。先に target repo 自体の存在/アクセスを確認し、外部 API probe には timeout と retry を付けて token 不備や一時的な network stall を明確に切り分ける。
- アクセシビリティ向けのテーマ提案では、任意設定だけで完結させず、すぐ選べる高コントラスト preset を別モードで持つかを先に確認する。利用者は `custom` より preset を期待していることがある。
- 既存 UI の見た目調整では、preset を追加するときも従来 preset の色味を不必要に変えない。default は既存の印象を保ち、新規テーマでだけ方向性を変える。
- optional config table を保存するときは、未設定 field を `""` でシリアライズしない。fallback 契約がある設定は key ごと omit して、ユーザー生成物にも契約そのものを反映する。
Expand Down
Loading