[[macOS]]ã¢ããª(JINRAI)ãé
åžããä»çµã¿ãã€ããã
## èŠä»¶
- ãªãªãŒã¹ã¯[[GitHub]]ã®CIã§è¡ã
- Apple Storeãžã®æ²èŒã¯äžèŠ
- ãéã¯æããããªã
- [[Homebrew]]ã[[mise]]ãªã©ã§ã€ã³ã¹ããŒã«ã§ãããšãªãè¯ã
- ããŒãžã§ã³ã¢ããã¯JINRAIã®ã¡ãã¥ãŒããè¡ããããã«ããã
- [[Homebrew]]ã[[mise]]ã§ãã§ãããšãã
## JINRAI é
åžæ©æ§ å®è£
ãã©ã³
### Context
JINRAI(SwiftPM 補 macOS ã¡ãã¥ãŒããŒåžžé§ã¢ããª)ã«ã¯ãŸã é
åžææ®µããªã(GitHub Releasesã»ã¿ã°ã»ãªãªãŒã¹ CI ãã¹ãŠæªæŽåãREADME ãéçºè
åããã«ãæé ã®ã¿)ããšã³ããŠãŒã¶ãŒãç°¡åã«ã€ã³ã¹ããŒã«ã»ã¢ããããŒãã§ããä»çµã¿ãäœãã
確å®ããæ¹é(ãŠãŒã¶ãŒãšåææžã¿):
- **Apple Developer Program ã¯äœ¿ããªã(ç¡æ)** â Developer ID 眲åã»å
¬èšŒãªã
- **ãªãªãŒã¹ã¯ GitHub Actions**(`v*` ã¿ã° push ããªã¬ãŒ)
- **眲åã¯èªå·±çœ²åèšŒææž `jinrai-dev` ãåºå®**: .p12 ã GitHub Secrets ã«ç»é²ã CI ã§çœ²åãad-hoc ã ãšæŽæ°æ¯ã«çœ²åãå€ãã TCC æš©é(ã¢ã¯ã»ã·ããªãã£ã»ç»é¢åé²)ãå¥ããããããããŒã«ã«éçºã® `make-app.sh` ãæ¢ã« `jinrai-dev` ãæ€çŽ¢ããå®è£
ãªã®ã§æµçšã§ãã
- **ã¡ãã¥ãŒããã®ã¢ããããŒãã¯èªåå®è£
**(Sparkle äžäœ¿çšãäŸåãŒã)
- **Homebrew ã¯èªå tap æ°èš**(`tadashi-aikawa/homebrew-tap`ãcaskãæ¢å tap ãªããžããªãªã)
- mise 察å¿ã¯èŠéã
### å®è£
ãã§ãŒãº
```
Phase 0: èšŒææžæºå(ãŠãŒã¶ãŒæäœæ¥ + Secrets ç»é²)
Phase 1: make-app.sh æ¡åŒµ + Info.plist ä¿®æ£
Phase 2: release.yml(ã¿ã° push â GitHub Release)
Phase 3: homebrew-tap æ°èš + cask èªåæŽæ°
Phase 4: èªåã¢ããããŒã¿(Swift å®è£
+ ã¡ãã¥ãŒçµ±å)
Phase 5: README / docs æŽæ°
Phase 6: æ€èšŒ(v0.0.1 ãã¹ããªãªãŒã¹)
```
Phase 2 ãŸã§ã§ãã¿ã°ãæãŠã° Release ãã§ãããç¶æ
ã«ãªããPhase 3/4 ã¯ç¬ç«ã«é²ããããã
### Phase 0: èªå·±çœ²åèšŒææžã®æºå(ãŠãŒã¶ãŒæäœæ¥)
ããŒã«ã«ã® `jinrai-dev` èšŒææžã CI ã§ã䜿ããå
šçµè·¯(éçºã»CI ãªãªãŒã¹ã»èªåæŽæ°)ã§çœ²åãçµ±äžããã
1. æªäœæãªã Keychain Access â èšŒææžã¢ã·ã¹ã¿ã³ã â ãèšŒææžãäœæâŠã
- åå `jinrai-dev` / èªå·±çœ²åã«ãŒã / ã¿ã€ã **ã³ãŒã眲å** / æå¹æé㯠3650 æ¥çã«å»¶é·æšå¥š(äœãçŽããš TCC ãå¥ããããã)
2. ç§å¯éµããš .p12 ã§æžãåºã(ãã¹ã¯ãŒãä»ã)â `base64 -i jinrai-dev.p12 | pbcopy`
3. jinrai ãªããžããªã® Secrets ã«ç»é²:
| Secret | å
容 |
| --- | --- |
| `MACOS_CERT_P12_BASE64` | .p12 ã® base64 |
| `MACOS_CERT_PASSWORD` | .p12 ã®ãã¹ã¯ãŒã |
| `TAP_GITHUB_TOKEN` | tap æŽæ°çš fine-grained PAT(Phase 3) |
keychain ãã¹ã¯ãŒãã¯ãžã§ãå
`openssl rand` çæã§ Secret äžèŠã
### Phase 1: äžæºå
- `Resources/Info.plist`:
- `NSScreenCaptureUsageDescription` 远å (çŸç¶æªèšå®)
- `LSMinimumSystemVersion` ã 14.0 â 15.0 ã«æŽå(README 㯠macOS 15+)
- `scripts/make-app.sh`:
- 眲å identity ãç°å¢å€æ° `CODESIGN_IDENTITY`(ããã©ã«ã `jinrai-dev`)ã§äžæžãå¯èœã«
- `--timestamp=none` ãæç€º(èªå·±çœ²åã¯ã¿ã€ã ã¹ã¿ã³ããµãŒãäžå¯)ãhardened runtime ã¯ä»ããªã(å
¬èšŒãªãã§ã¯å©ç¹ãªã)
### Phase 2: `.github/workflows/release.yml`(æ°èŠ)
- ããªã¬ãŒ `push: tags: ["v*"]`ã`runs-on: macos-26`(ci.yml ãšåã SDK äžä»£)ã`permissions: contents: write`
- **èšŒææž import**: `security create-keychain` â `import -T /usr/bin/codesign` â `set-key-partition-list -S apple-tool:,apple:,codesign:`(ç¡ããš codesign ããã³ã°)â `security list-keychains -d user -s` ã§ search list ã«è¿œå (make-app.sh ã® `find-identity` ãèŠã€ããããã«å¿
é )
- `VERSION=${GITHUB_REF_NAME#v}` â `./scripts/make-app.sh release "$VERSION"`
- **çœ²åæ€èšŒã¹ãããå¿
é **: `codesign -dv .build/JINRAI.app 2>&1 | grep -q "Authority=jinrai-dev"` â ad-hoc ãã©ãŒã«ããã¯ã§ãªãªãŒã¹ãããäºæ
ã fail ã§é²ã(ad-hoc ã ãšæŽæ°æ¯ã« TCC ãå¥ããã)
- **ã¢ãŒã«ã€ã㯠zip(`ditto -c -k --keepParent`)**: æ¡åŒµå±æ§ã»çœ²åã¡ã¿ããŒã¿ãä¿æãããã«ã¯ãªãã¯å±éå¯ãcask æšæºå¯Ÿå¿ã`--keepParent` å¿
é
- `gh release create "$GITHUB_REF_NAME" JINRAI-$VERSION.zip --generate-notes`
- **tap æŽæ°**: `TAP_GITHUB_TOKEN`(fine-grained PATãhomebrew-tap ã®ã¿ã»Contents write ã®ã¿)ã§ tap ã clone â `Casks/jinrai.rb` ã® version/sha256 ãæžãæã â commit & push
### Phase 3: `tadashi-aikawa/homebrew-tap`(æ°èŠãªããžããª)
æ§æ: `README.md` + `Casks/jinrai.rb`
cask ã®èŠç¹:
- `url "https://github.com/tadashi-aikawa/jinrai/releases/download/v#{version}/JINRAI-#{version}.zip"`
- `app "JINRAI.app"`(/Applications ãžç§»åããã)ã`depends_on macos: ">= :sequoia"`
- **quarantine 察åŠ**: èªå tap ã®ç¹æš©ãšã㊠`postflight` ã§ `xattr -dr com.apple.quarantine` ãå®è¡(`--no-quarantine` ãã©ã°é Œã¿ã¯å¿ãããã)ã念ã®ãã caveats ã«ã Gatekeeper æé ãèšèŒ
- ã€ã³ã¹ããŒã«ã§ `brew install tadashi-aikawa/tap/jinrai` ã䜿ããããã«ãªã
### Phase 4: èªåã¢ããããŒã¿
æ°èŠãã¡ã€ã«(æ¢å Features/ ãã¿ãŒã³èžè¥²):
| ãã¡ã€ã« | åœ¹å² |
| --- | --- |
| `Sources/JinraiCore/SemanticVersion.swift` | ããŒãžã§ã³è§£æã»æ¯èŒ(çŽç²ããžãã¯ããã¹ã察象) |
| `Tests/JinraiCoreTests/SemanticVersionTests.swift` | äžèšã®ãã¹ã |
| `Sources/Jinrai/Features/Updater/UpdateChecker.swift` | GitHub Releases API(`releases/latest`ãèªèšŒäžèŠ)ã§ææ°çå€å® |
| `Sources/Jinrai/Features/Updater/UpdateInstaller.swift` | DL â å±é â 眮æ â åèµ·å |
| `Sources/Jinrai/Features/Updater/UpdaterFeature.swift` | UI ãããŒçµ±æ¬(NSAlert ããŒã¹) |
èšèšã®èŠç¹:
- `0.0.0-development` ã§ã¯ãã§ãã¯ãã¹ããã(éçº .app ã®èª€äžæžã鲿¢)
- ã€ã³ã¹ããŒã«ãããŒ: `URLSession.download` â `ditto -x -k` ã§å±é â 眮æåã« `codesign --verify` + designated requirement æ¯èŒ â **rename 2 åæ¹åŒã§çœ®æ**(å®è¡äž .app ã® rename ã¯å¯èœãSparkle çãã«ããŒäžèŠ)â `sh -c 'sleep 0.5; open <path>'` ã detach ã㊠`NSApp.terminate`
- quarantine: `LSFileQuarantineEnabled` æªèšå®ãªã URLSession DL ã«ã¯ä»ããªãã¯ãã ããé²åŸ¡çã«å±éåŸ xattr é€å»ãç¡æ¡ä»¶å®è¡
- **brew ã€ã³ã¹ããŒã«æ€ç¥æ**(`Caskroom/jinrai` ååšãã§ãã¯)ã¯èªåæŽæ°ãã¹ãããã `brew upgrade --cask jinrai` ãæ¡å
(brew ãšã® version/sha256 ä¹é¢ãåé¿)ãèªåæŽæ°ã¯æåã€ã³ã¹ããŒã«ãŠãŒã¶ãŒåã
- `StatusItem.swift`: ããŒãžã§ã³è¡šç€ºçŽåŸã«ãã¢ããããŒãã確èªâŠãé
ç® + `onCheckForUpdates` ã¯ããŒãžã£(æ¢å `onReloadConfig` ãã¿ãŒã³èžè¥²)ã`AppDelegate.swift` ã§ `UpdaterFeature` ãçµç·
- UI: ææ°ãªããææ°çã§ãããæ°çãããªã [æŽæ°]/[ãªãªãŒã¹ããŒããèŠã]/[ãã£ã³ã»ã«]ããšã©ãŒæã¯ Releases ããŒãžãžèªå°ããã¹ãŠ NSAlert
### Phase 5: ããã¥ã¡ã³ã
`README.md` ã«ã€ã³ã¹ããŒã«ã»ã¯ã·ã§ã³è¿œå :
1. Homebrew: `brew install tadashi-aikawa/tap/jinrai`
2. æå: Releases ãã zip â å±é â /Applications
3. **ååèµ·å(Gatekeeper)**: macOS 15+ ã¯å³ã¯ãªãã¯âéããã€ãã¹ã廿¢æžã¿ãããã«ã¯ãªã㯠â ããã㯠â ã·ã¹ãã èšå® â ãã©ã€ãã·ãŒãšã»ãã¥ãªã㣠â **ããã®ãŸãŸéãã**ã代æ¿: `xattr -dr com.apple.quarantine`(brew çµç±ãªãäžèŠ)
4. éçºè
åã: èšŒææžäœæã»Secretsã»ãªãªãŒã¹æé (`git tag vX.Y.Z && git push origin vX.Y.Z`)
`docs/docs/setup.md` ã¯æ§ Hammerspoon çã®å
容ãªã®ã§ããã€ãã£ãçã®æé ã«æžãæã(docs/ ã¯æªã³ãããã®ããæ±ãã¯å®è£
æã«ãŠãŒã¶ãŒãšçžè«)ã
### Phase 6: æ€èšŒ
1. ããŒã«ã«: `./scripts/make-app.sh release 9.9.9` â `codesign -dv` ã§ Authority=jinrai-dev 確èª
2. keychain import æé ãããŒã«ã«ã®äžæ keychain ã§åçŸããé察話眲åãéãããšã確èª
3. `ditto` åŸåŸ© â `codesign --verify --deep` ãéãããš
4. `v0.0.1` ãã¹ãã¿ã° push â release.yml å
šè¡çšç¢ºèª(tap æŽæ°ã¯æåã³ã¡ã³ãã¢ãŠãããŠæ®µéæå
¥)
5. `brew install` â quarantine ãå€ããŠãã(`xattr -l`)ã»èµ·åç¢ºèª â `brew upgrade` äžå·¡
6. æ§ç 0.0.1 ã /Applications ã«çœ®ããŠèµ·å â æ°çãªãªãŒã¹ â ã¡ãã¥ãŒæŽæ° â **眮æåŸã« TCC æš©é(ã¢ã¯ã»ã·ããªãã£ã»ç»é¢åé²)ãç¶æãããŠããã確èª(æéèŠ)**
7. ãã©ãŠã¶å®ããŠã³ããŒãã§ Gatekeeper æé (ããã®ãŸãŸéãã)ã宿©ç¢ºèª
### å®è£
æã«æ€èšŒãã¹ãäžç¢ºã㪠macOS 仿§
1. **TCC ç¶æ(æéèŠ)**: åäžèªå·±çœ²åã§ã®çœ®ãæãåŸã«æš©éãæ®ãã(macOS 26 宿©)
2. URLSession DL ãžã® quarantine ä»äžæç¡
3. `open` ã«ãã relaunch ã®ã¿ã€ãã³ã°(`-n` ã®èŠåŠ)
4. cask postflight ã® xattr é€å»ã brew ãµã³ãããã¯ã¹äžã§åãã
5. `set-key-partition-list` ã®ãªãã·ã§ã³ãã©ã³ããŒäžä»£ã§å€ãããªãã
### 倿Žã»æ°èŠãã¡ã€ã«äžèЧ
| çš®å¥ | ãã¡ã€ã« |
| --- | --- |
| æ°èŠ | `.github/workflows/release.yml` |
| å€æŽ | `scripts/make-app.sh` / `Resources/Info.plist` |
| æ°èŠ | `Sources/JinraiCore/SemanticVersion.swift` + ãã¹ã |
| æ°èŠ | `Sources/Jinrai/Features/Updater/`(3ãã¡ã€ã«) |
| å€æŽ | `Sources/Jinrai/StatusItem.swift` / `AppDelegate.swift` |
| å€æŽ | `README.md`(docs/ ã¯å®è£
æã«çžè«) |
| æ°èŠ(å¥ãªããžããª) | `tadashi-aikawa/homebrew-tap` â `Casks/jinrai.rb` |
## å®äºå ±å
å®è£
å
容
jinrai ãªããžããª(æªã³ãããã®å€æŽ):
- .github/workflows/release.yml(æ°èŠ) â v* ã¿ã° push ã§ãèªå·±çœ²åèšŒææžã® import â ãã«ã â çœ²åæ€èšŒ â ditto zip å â GitHub Release äœæ â tap ã® cask èªåæŽæ°ãŸã§å®è¡
- scripts/make-app.sh â CODESIGN_IDENTITY ç°å¢å€æ°å¯Ÿå¿ãš --timestamp=none 远å
- Resources/Info.plist â NSScreenCaptureUsageDescription 远å ãæå°ããŒãžã§ã³ã 15.0 ã«æŽå
- èªåã¢ããããŒã¿(äŸåãŒã) â ã¡ãã¥ãŒã«ãã¢ããããŒãã確èªâŠãã远å ãGitHub Releases API ã§ææ°çç¢ºèª â ããŠã³ããŒã â çœ²åæ€èšŒ(çŸè¡ãšåã jinrai-dev 眲åã§ãªããã°æåŠ)â rename 2åæ¹åŒã§çœ®ãæã â èªååèµ·åãéçºãã«ã(0.0.0-development)ã§ã¯ã¹ããããHomebrew çµç±ã€ã³ã¹ããŒã«æã¯ brew upgrade --cask jinrai ãæ¡å
ããŠä¹é¢ãåé¿
- README.md â ã€ã³ã¹ããŒã«æé (brew / æå / Gatekeeperããã®ãŸãŸéããæé )ãšãªãªãŒã¹æé ã远èš
æ°èŠãªããžããª: https://github.com/tadashi-aikawa/homebrew-tap ãäœæã»push æžã¿ãbrew install tadashi-aikawa/tap/jinrai çšã® cask ãé
眮ããquarantine 㯠postflight ã§èªåé€å»ããŸã(cask ã® version/sha256 ã¯ååãªãªãŒã¹æã« CI ãæžãæããŸã)ã
æ€èšŒã§1ä»¶ãã°ãçºèŠã»ä¿®æ£æžã¿: çœ²åæ€èšŒã® codesign -dv ã§ã¯ Authority è¡ãåºåããã CI ãå¿
ã fail ããç¶æ
ã ã£ãããã-dvv ã«ä¿®æ£ããŸããããŸã codesign -dr - ã®å®åºåãããTCC ã®å€å®ããŒãããã³ãã« ID + èšŒææžãªãŒãããã·ã¥ãã§ããããšã確èªã§ããåäžèšŒææžã§ã®æŽæ°ãªãæš©éãç¶æãããèšèšã®åæãè£ä»ããããŸããã
ãªãªãŒã¹åã«å¿
èŠãªæäœæ¥(ããªãã®æäœ)
1. èšŒææžã®ãšã¯ã¹ããŒã: Keychain Access ã§ jinrai-dev(æ¢åãç¢ºèªæžã¿)ãç§å¯éµããš .p12 圢åŒã§æžãåºã â base64 -i jinrai-dev.p12 | pbcopy
2. jinrai ãªããžããªã® Secrets ç»é²: MACOS_CERT_P12_BASE64 / MACOS_CERT_PASSWORD / TAP_GITHUB_TOKEN(fine-grained PATã察象㯠homebrew-tap ã®ã¿ã»Contents: Read and write)
3. ãã¹ããªãªãŒã¹: git tag v0.0.1 && git push origin v0.0.1 ã§ã¯ãŒã¯ãããŒå
šè¡çšã確èª
4. 宿©æ€èšŒ(æéèŠ): æ§çãèµ·åããç¶æ
ã§ã¡ãã¥ãŒããæŽæ°ããã¢ã¯ã»ã·ããªãã£ã»ç»é¢åé²ã®èš±å¯ãç¶æãããã確èªããã©ãŠã¶å®ããŠã³ããŒãã§ã® Gatekeeper æé ãäžåºŠç¢ºèªãæšå¥š
ãªã docs/(æªã³ããã)ã¯æ§ Hammerspoon çã®å
容ã®ãŸãŸãªã®ã§ä»åã¯è§Šã£ãŠããŸããããã€ãã£ãçåãã®æžãæããå¿
èŠã«ãªã£ãã声ããããŠãã ããã
## æåäœæ¥
### 1. èšŒææžã®ãšã¯ã¹ããŒã: Keychain Access ã§ jinrai-dev(æ¢åãç¢ºèªæžã¿)ãç§å¯éµããš .p12 圢åŒã§æžãåºã
1. Keychain Access(ããŒãã§ãŒã³ã¢ã¯ã»ã¹).app ãéã(Spotlight ã§ãããŒãã§ãŒã³ã¢ã¯ã»ã¹ã)
2. å·ŠåŽã§ããã°ã€ã³ãããŒãã§ãŒã³ â åé¡ãèªåã®èšŒææžããéžæ
3. jinrai-dev ãæ¢ããå·Šã® â¶ ãéããšç§å¯éµãã¶ãäžãã£ãŠããã¯ã
4. èšŒææžã®è¡(芪)ãå³ã¯ãªã㯠â ã"jinrai-dev"ãæžãåºãâŠã
- åé¡ãèªåã®èšŒææžãããæžãåºããšç§å¯éµãäžç·ã«å«ãŸããŸã
5. ãã©ãŒããã㯠ãå人æ
å ±äº€æ(.p12)ã ãéžæãä¿åå
ã¯ä»»æ(äŸ: ~/Downloads/jinrai-dev.p12)
6. ãã¹ã¯ãŒããèšå®(ããã Secrets ã® MACOS_CERT_PASSWORD ã«ãªããŸã)
- ããŒã«ã«ã®ç§å¯æ
å ±é
äžã« `MACOS_CERT_PASSWORD_JINRAI`
7. base64 åããŠã¯ãªããããŒããž:
- `base64 -i ~/Downloads/jinrai-dev.p12 | pbcopy`
8. [[ðŠJINRAI]]ã® `Secrets and variables` > `Actions` > `Secrets` > `Repository secrets` ã«
- `MACOS_CERT_P12_BASE64` ã«è²Œãä»ã
- `MACOS_CERT_PASSWORD` ã«æé 6ã®ãã¹ã¯ãŒã
### 2. jinrai ãªããžããªã® Secrets ç»é²
[[Fine-grained personal access token (GitHub)|Fine-grained personal access token]] ãšããŠäœæã
![[2026-07-05-10-18-15.avif]]
[[ðŠJINRAI]]ã® `Secrets and variables` > `Actions` > `Secrets` > `Repository secrets` ã« `TAP_GITHUB_TOKEN` ãšããŠç»é²ã
### 3. ãã¹ããªãªãŒã¹
```console
git tag v0.0.1 && git push origin v0.0.1
```
æåãããš `jinrai.rb` ãæžãæããã
https://github.com/tadashi-aikawa/homebrew-tap/blob/main/Casks/jinrai.rb
> [!error]- ãã¹ã¯ãŒããããããå Žå
> 以äžã®ãããªãšã©ãŒã«ãªã
>
> ```error
> security: SecKeychainItemImport: MAC verification failed during PKCS12 import (wrong password?)
> Error: Process completed with exit code 1.
> ```
>
> ãã¹ã¯ãŒããæ£ãããã®ç¢ºèªã¯ä»¥äžã
>
> ```console
> openssl pkcs12 -in ~/Downloads/jinrai-dev.p12 -info -noout -passin 'pass:<ãã¹ã¯ãŒã>'
> ```
### 4. ã€ã³ã¹ããŒã«ãšåäœç¢ºèª
ãŸãã¯éçºçã忢ã
```console
pkill -x JINRAI
```
tapæå®ã§ã€ã³ã¹ããŒã«ã
```console
brew install tadashi-aikawa/tap/jinrai
```
ã€ã³ã¹ããŒã«åŸã[[Raycast]]ã«è¡šç€ºãããããšã確èªãèµ·åãã§ããã
![[2026-07-05-10-47-39.avif]]
ä»ã®ç¢ºèªé
ç®ã
```bash
# /Applications ã«é
眮ãããŠããã
$ ls -d /Applications/JINRAI.app
/Applications/JINRAI.app
# quarantine ãå€ããŠããã(postflight ãå¹ããŠããã°äœã衚瀺ãããªãã®ãæ£è§£)
$ xattr -l /Applications/JINRAI.app | grep quarantine
# 眲åã jinrai-dev ã
$ codesign -dvv /Applications/JINRAI.app 2>&1 | grep Authority
Authority=jinrai-dev
```
### 5. ã¢ã³ã€ã³ã¹ããŒã«
```console
brew uninstall --cask jinrai
```
èµ·åäžã®ããã»ã¹ã¯åæ¢ããªããã©çްããåé¡ãªã®ã§OKãæ¢ããããã°ä»¥äžãå®è¡ããŠããã
```console
pkill -x JINRAI
```
åã€ã³ã¹ããŒã«ã®ç¢ºèªãããŠããã
```console
brew install tadashi-aikawa/tap/jinrai
```
## [[semantic-release]]察å¿
ãªãªãŒã¹ã®ãã³ã«ãªãªãŒã¹ããŒããäœæãããããŒãžã§ã³æå®ããã®ã¯é¢åãªã®ã§ã
### ãã©ã³
#### Context
çŸåšã® jinrai 㯠`v*` ã¿ã°ãæåã§ push ãããš release.yml ãèµ·åãããã«ã â 眲å â zip â GitHub Release â Homebrew tap æŽæ°ãŸã§èªåå®è¡ããããããã jinrai-spoon ãšåã semantic-release æ¹åŒã«å€æŽãã**GitHub Actions ã® Release ã¯ãŒã¯ãããŒãæåå®è¡(workflow_dispatch)ããã ã**ã§ãconventional commits ããããŒãžã§ã³ç®åº â ã¿ã°äœæ â ãªãªãŒã¹ãŸã§å
šèªåã«ãªãããã«ããã
åæã®ç¢ºèªçµæ:
- jinrai ã«ã¯ `v0.0.1` ã¿ã°ã»ãªãªãŒã¹ãæ¢ã«ååš(remote ã«ããã)â semantic-release ã¯ãããèµ·ç¹ã«æ¬¡ããŒãžã§ã³ãç®åºããã®ã§ãååãªãªãŒã¹ã 1.0.0 ã«ãªããåé¡ã¯èµ·ããªã
- ãªãªãŒã¹ã¢ã»ããå㯠`JINRAI-<version>.zip` åºå®(`UpdateChecker.swift:68` ããã®ååã§ã¢ã»ãããæ¢ããã倿Žäžå¯)
- ã³ããã㯠conventional commits 圢åŒ(feat/fix/style/docs/ci...)ã§éçšæžã¿
#### 倿Žå
容
##### 1. `release.config.cjs`(æ°èŠ)
jinrai-spoon ã® `release.config.cjs` ãããŒã¹ã«ã³ããŒã倿Žç¹:
- `@semantic-release/exec`:
- `prepareCmd: "./scripts/build_release.sh ${nextRelease.version}"`
- `successCmd: "./scripts/update_tap.sh ${nextRelease.version}"`(GitHub Release æååŸã« tap æŽæ°)
- `@semantic-release/github` ã® assets: `{ path: "dist/JINRAI-*.zip", label: "JINRAI.app" }`(ã¢ã»ãããã¹ã¯ããŒãžã§ã³å€æ°ãå±éã§ããªããã glob ã§æå®)
- releaseRules / release-notes ã®çµµæåã»ã¯ã·ã§ã³å®çŸ©ã¯ spoon ãšåäž(breaking â minor ã® pre-v1 ã«ãŒã«ãèžè¥²ãTODO ã³ã¡ã³ããç¶æ)
##### 2. `scripts/build_release.sh`(æ°èŠ)
spoon ã® `scripts/build_release.sh` ã«çžåœãçŸè¡ release.yml ã®ãã«ããzip ã¹ããããç§»æ€:
1. åŒæ°ããŒãžã§ã³ã® semver æ€èšŒ
2. `./scripts/make-app.sh release "$VERSION"`(æ¢åã¹ã¯ãªããããã®ãŸãŸå©çš)
3. `codesign -dvv` ã§ `Authority=jinrai-dev` ãæ€èšŒ(ad-hoc ãã©ãŒã«ããã¯äºæ
鲿¢ãçŸè¡ release.yml:47-49 ãšåã)
4. `ditto -c -k --keepParent .build/JINRAI.app "dist/JINRAI-$VERSION.zip"`
5. zip ã®ååšæ€èšŒ
##### 3. `scripts/update_tap.sh`(æ°èŠ)
çŸè¡ release.yml ã®ãUpdate Homebrew tapãã¹ããã(63-77è¡)ãã¹ã¯ãªããå:
- åŒæ°ããŒãžã§ã³ãã `dist/JINRAI-$VERSION.zip` ã® sha256 ãèšç®
- `TAP_GITHUB_TOKEN` ç°å¢å€æ°ã§ homebrew-tap ã clone ãã`Casks/jinrai.rb` ã® version/sha256 ã sed ã§æžãæã㊠commit/push
##### 4. `.github/workflows/release.yml`(æžãæã)
spoon ã® release.yml ã®æ§æã«ãjinrai åºæã®çœ²åãŸãããåæ:
- ããªã¬: `workflow_dispatch`(ã¿ã° push ããªã¬ã¯å»æ¢)
- main ãã©ã³ã以å€ãªãäžæããã¬ãŒã
- `runs-on: macos-26`(Swift ãã«ããš codesign ãå¿
èŠãªãããspoon ã® ubuntu ã§ã¯ãªãçŸè¡èžè¥²)
- èšŒææž import ã¹ãããã¯çŸè¡ã®ãŸãŸç¶æ(release.yml:20-38)
- `actions/checkout@v6` + `fetch-depth: 0`(semantic-release ãã¿ã°å±¥æŽãèªãããå¿
é )
- Node.js 24 + pnpm ã»ããã¢ããåŸãspoon ãšåã `pnpm dlx --package
[email protected] --package
[email protected] --package @semantic-release/exec semantic-release` ãå®è¡
- env: `GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}`, `TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }}`
- `permissions: contents: write` ã¯ç¶æ(semantic-release ãã¿ã° pushã»Release äœæã«äœ¿çš)
##### 5. `README.md` ã®ãªãªãŒã¹ç¯æŽæ°
ãã¿ã°ã push ãããæé ããActions ã® Release ã¯ãŒã¯ãããŒãæåå®è¡ãããã«æžãæããããŒãžã§ã³ã¯ conventional commits ããèªå決å®ãããæšãèšèŒ(ã°ããŒãã«ã® `/release` ã³ãã³ãã README ãåç
§ããŠå®è¡ããããããããæ£ç¢ºã§ããããšãéèŠ)ã
#### 倿Žããªããã®
- `scripts/make-app.sh` / `Resources/Info.plist` ã®ããŒãžã§ã³åãèŸŒã¿æ©æ§(ãã®ãŸãŸ build_release.sh ããå©çš)
- `ci.yml`
- ãªãªãŒã¹ããŒãçæã¯ `--generate-notes` ãã semantic-release ã® conventionalcommits ããªã»ãã(çµµæåã»ã¯ã·ã§ã³)ã«å€ãã
#### æ€èšŒæ¹æ³
1. ããŒã«ã«ã§ `./scripts/build_release.sh 0.0.0-test` ãå®è¡ãã`dist/JINRAI-0.0.0-test.zip` ãçæãããããšã確èª(ããŒã«ã«ã¯ jinrai-dev èšŒææžããªããã°çœ²åæ€èšŒã¯ã¹ããã or CI ã®ã¿ã§æ€èšŒããããåå² â spoon ã® ci.yml ã `0.0.0-test` ã§ãã«ãæ€èšŒããŠããã®ãšåæ§)
- 泚: çœ²åæ€èšŒ(Authority=jinrai-dev)ã¯ããŒã«ã«ã«èšŒææžãããã°éãããªããã°ãã®ã¹ãããã ã CI äŸå
2. `pnpm dlx ... semantic-release --dry-run` ãããŒã«ã«ã§å®è¡ããrelease.config.cjs ã®æ§æã𿬡ããŒãžã§ã³ç®åºã確èª(GITHUB_TOKEN å¿
èŠ)
3. ã³ãããã»push åŸãGitHub Actions ã§ Release ã¯ãŒã¯ãããŒãæåå®è¡ãã以äžã確èª:
- æ°ããŒãžã§ã³ã®ã¿ã°ã»GitHub Release ãäœæããã`JINRAI-<version>.zip` ãæ·»ä»ãããŠãã
- ãªãªãŒã¹ããŒããçµµæåã»ã¯ã·ã§ã³ä»ãã§çæãããŠãã
- homebrew-tap ã® `Casks/jinrai.rb` ãæŽæ°ãããŠãã
## ã¢ããããŒãã®ãã¹ã
ãŸã㯠**æ°ããããŒãžã§ã³ããªãç¶æ
ã§** 以äžãå®è¡ãäœãèµ·ãããªããã°OKã
```console
brew upgrade --cask jinrai
```
次㮠**æ°ããããŒãžã§ã³ããªãªãŒã¹ããŠãã** å®è¡ã
```console
pkill -x JINRAI
brew update
brew upgrade --cask jinrai
```
ããã§æŽæ°ã»åèµ·åããã°OKã