publish.yml 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. name: publish
  2. run-name: "${{ format('release {0}', inputs.bump) }}"
  3. on:
  4. push:
  5. branches:
  6. - ci
  7. - dev
  8. - beta
  9. - snapshot-*
  10. workflow_dispatch:
  11. inputs:
  12. bump:
  13. description: "Bump major, minor, or patch"
  14. required: false
  15. type: choice
  16. options:
  17. - major
  18. - minor
  19. - patch
  20. version:
  21. description: "Override version (optional)"
  22. required: false
  23. type: string
  24. concurrency: ${{ github.workflow }}-${{ github.ref }}-${{ inputs.version || inputs.bump }}
  25. permissions:
  26. id-token: write
  27. contents: write
  28. packages: write
  29. jobs:
  30. version:
  31. runs-on: blacksmith-4vcpu-ubuntu-2404
  32. if: github.repository == 'anomalyco/opencode'
  33. steps:
  34. - uses: actions/checkout@v3
  35. with:
  36. fetch-depth: 0
  37. - uses: ./.github/actions/setup-bun
  38. - name: Setup git committer
  39. id: committer
  40. uses: ./.github/actions/setup-git-committer
  41. with:
  42. opencode-app-id: ${{ vars.OPENCODE_APP_ID }}
  43. opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
  44. - name: Install OpenCode
  45. if: inputs.bump || inputs.version
  46. run: bun i -g opencode-ai
  47. - id: version
  48. run: |
  49. ./script/version.ts
  50. env:
  51. GH_TOKEN: ${{ steps.committer.outputs.token }}
  52. OPENCODE_BUMP: ${{ inputs.bump }}
  53. OPENCODE_VERSION: ${{ inputs.version }}
  54. OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
  55. GH_REPO: ${{ (github.ref_name == 'beta' && 'anomalyco/opencode-beta') || github.repository }}
  56. outputs:
  57. version: ${{ steps.version.outputs.version }}
  58. release: ${{ steps.version.outputs.release }}
  59. tag: ${{ steps.version.outputs.tag }}
  60. repo: ${{ steps.version.outputs.repo }}
  61. build-cli-linux-win:
  62. needs: version
  63. runs-on: blacksmith-4vcpu-ubuntu-2404
  64. if: github.repository == 'anomalyco/opencode'
  65. steps:
  66. - uses: actions/checkout@v3
  67. with:
  68. fetch-tags: true
  69. - uses: ./.github/actions/setup-bun
  70. - name: Setup git committer
  71. id: committer
  72. uses: ./.github/actions/setup-git-committer
  73. with:
  74. opencode-app-id: ${{ vars.OPENCODE_APP_ID }}
  75. opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
  76. - name: Build
  77. id: build
  78. run: |
  79. ./packages/opencode/script/build.ts
  80. env:
  81. OPENCODE_VERSION: ${{ needs.version.outputs.version }}
  82. OPENCODE_RELEASE: ${{ needs.version.outputs.release }}
  83. GH_REPO: ${{ needs.version.outputs.repo }}
  84. GH_TOKEN: ${{ steps.committer.outputs.token }}
  85. OPENCODE_BUILD_OS: linux,win32
  86. OPENCODE_SKIP_RELEASE_UPLOAD: "1"
  87. - uses: actions/upload-artifact@v4
  88. with:
  89. name: opencode-cli-linux-win
  90. path: packages/opencode/dist
  91. build-cli-darwin:
  92. needs: version
  93. runs-on: macos-latest
  94. if: github.repository == 'anomalyco/opencode'
  95. steps:
  96. - uses: actions/checkout@v3
  97. with:
  98. fetch-tags: true
  99. - uses: ./.github/actions/setup-bun
  100. - name: Setup git committer
  101. id: committer
  102. uses: ./.github/actions/setup-git-committer
  103. with:
  104. opencode-app-id: ${{ vars.OPENCODE_APP_ID }}
  105. opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
  106. - uses: apple-actions/import-codesign-certs@v2
  107. with:
  108. keychain: build
  109. p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }}
  110. p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
  111. - name: Resolve signing identity
  112. run: |
  113. CERT_INFO=$(security find-identity -v -p codesigning build.keychain | grep "Developer ID Application")
  114. CERT_ID=$(echo "$CERT_INFO" | awk -F'"' '{print $2}')
  115. if [ -z "$CERT_ID" ]; then
  116. echo "Developer ID Application identity not found"
  117. exit 1
  118. fi
  119. echo "CERT_ID=$CERT_ID" >> $GITHUB_ENV
  120. - name: Build
  121. id: build
  122. run: |
  123. ./packages/opencode/script/build.ts
  124. env:
  125. OPENCODE_VERSION: ${{ needs.version.outputs.version }}
  126. OPENCODE_RELEASE: ${{ needs.version.outputs.release }}
  127. GH_REPO: ${{ needs.version.outputs.repo }}
  128. GH_TOKEN: ${{ steps.committer.outputs.token }}
  129. APPLE_SIGNING_IDENTITY: ${{ env.CERT_ID }}
  130. OPENCODE_BUILD_OS: darwin
  131. OPENCODE_SKIP_RELEASE_UPLOAD: "1"
  132. - name: Verify darwin signatures
  133. run: |
  134. for file in packages/opencode/dist/opencode-darwin-*/bin/opencode; do
  135. codesign -vvv --verify "$file"
  136. done
  137. - uses: actions/upload-artifact@v4
  138. with:
  139. name: opencode-cli-darwin
  140. path: packages/opencode/dist
  141. build-tauri:
  142. needs:
  143. - version
  144. continue-on-error: false
  145. strategy:
  146. fail-fast: false
  147. matrix:
  148. settings:
  149. - host: macos-latest
  150. target: x86_64-apple-darwin
  151. - host: macos-latest
  152. target: aarch64-apple-darwin
  153. # github-hosted: blacksmith lacks ARM64 MSVC cross-compilation toolchain
  154. - host: windows-2025
  155. target: aarch64-pc-windows-msvc
  156. - host: blacksmith-4vcpu-windows-2025
  157. target: x86_64-pc-windows-msvc
  158. - host: blacksmith-4vcpu-ubuntu-2404
  159. target: x86_64-unknown-linux-gnu
  160. - host: blacksmith-8vcpu-ubuntu-2404-arm
  161. target: aarch64-unknown-linux-gnu
  162. runs-on: ${{ matrix.settings.host }}
  163. steps:
  164. - uses: actions/checkout@v3
  165. with:
  166. fetch-tags: true
  167. - uses: apple-actions/import-codesign-certs@v2
  168. if: ${{ runner.os == 'macOS' }}
  169. with:
  170. keychain: build
  171. p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }}
  172. p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
  173. - name: Verify Certificate
  174. if: ${{ runner.os == 'macOS' }}
  175. run: |
  176. CERT_INFO=$(security find-identity -v -p codesigning build.keychain | grep "Developer ID Application")
  177. CERT_ID=$(echo "$CERT_INFO" | awk -F'"' '{print $2}')
  178. echo "CERT_ID=$CERT_ID" >> $GITHUB_ENV
  179. echo "Certificate imported."
  180. - name: Setup Apple API Key
  181. if: ${{ runner.os == 'macOS' }}
  182. run: |
  183. echo "${{ secrets.APPLE_API_KEY_PATH }}" > $RUNNER_TEMP/apple-api-key.p8
  184. - uses: ./.github/actions/setup-bun
  185. - uses: actions/setup-node@v4
  186. with:
  187. node-version: "24"
  188. - name: Cache apt packages
  189. if: contains(matrix.settings.host, 'ubuntu')
  190. uses: actions/cache@v4
  191. with:
  192. path: ~/apt-cache
  193. key: ${{ runner.os }}-${{ matrix.settings.target }}-apt-${{ hashFiles('.github/workflows/publish.yml') }}
  194. restore-keys: |
  195. ${{ runner.os }}-${{ matrix.settings.target }}-apt-
  196. - name: install dependencies (ubuntu only)
  197. if: contains(matrix.settings.host, 'ubuntu')
  198. run: |
  199. mkdir -p ~/apt-cache && chmod -R a+rw ~/apt-cache
  200. sudo apt-get update
  201. sudo apt-get install -y --no-install-recommends -o dir::cache::archives="$HOME/apt-cache" libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
  202. sudo chmod -R a+rw ~/apt-cache
  203. - name: install Rust stable
  204. uses: dtolnay/rust-toolchain@stable
  205. with:
  206. targets: ${{ matrix.settings.target }}
  207. - uses: Swatinem/rust-cache@v2
  208. with:
  209. workspaces: packages/desktop/src-tauri
  210. shared-key: ${{ matrix.settings.target }}
  211. - name: Prepare
  212. run: |
  213. cd packages/desktop
  214. bun ./scripts/prepare.ts
  215. env:
  216. OPENCODE_VERSION: ${{ needs.version.outputs.version }}
  217. GITHUB_TOKEN: ${{ steps.committer.outputs.token }}
  218. RUST_TARGET: ${{ matrix.settings.target }}
  219. GH_TOKEN: ${{ github.token }}
  220. GITHUB_RUN_ID: ${{ github.run_id }}
  221. - name: Resolve tauri portable SHA
  222. if: contains(matrix.settings.host, 'ubuntu')
  223. run: echo "TAURI_PORTABLE_SHA=$(git ls-remote https://github.com/tauri-apps/tauri.git refs/heads/feat/truly-portable-appimage | cut -f1)" >> "$GITHUB_ENV"
  224. # Fixes AppImage build issues, can be removed when https://github.com/tauri-apps/tauri/pull/12491 is released
  225. - name: Install tauri-cli from portable appimage branch
  226. uses: taiki-e/cache-cargo-install-action@v3
  227. if: contains(matrix.settings.host, 'ubuntu')
  228. with:
  229. tool: tauri-cli
  230. git: https://github.com/tauri-apps/tauri
  231. # branch: feat/truly-portable-appimage
  232. rev: ${{ env.TAURI_PORTABLE_SHA }}
  233. - name: Show tauri-cli version
  234. if: contains(matrix.settings.host, 'ubuntu')
  235. run: cargo tauri --version
  236. - name: Setup git committer
  237. id: committer
  238. uses: ./.github/actions/setup-git-committer
  239. with:
  240. opencode-app-id: ${{ vars.OPENCODE_APP_ID }}
  241. opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
  242. - name: Build and upload artifacts
  243. uses: tauri-apps/tauri-action@390cbe447412ced1303d35abe75287949e43437a
  244. timeout-minutes: 60
  245. with:
  246. projectPath: packages/desktop
  247. uploadWorkflowArtifacts: true
  248. tauriScript: ${{ (contains(matrix.settings.host, 'ubuntu') && 'cargo tauri') || '' }}
  249. args: --target ${{ matrix.settings.target }} --config ${{ (github.ref_name == 'beta' && './src-tauri/tauri.beta.conf.json') || './src-tauri/tauri.prod.conf.json' }} --verbose
  250. updaterJsonPreferNsis: true
  251. releaseId: ${{ needs.version.outputs.release }}
  252. tagName: ${{ needs.version.outputs.tag }}
  253. releaseDraft: true
  254. releaseAssetNamePattern: opencode-desktop-[platform]-[arch][ext]
  255. repo: ${{ (github.ref_name == 'beta' && 'opencode-beta') || '' }}
  256. releaseCommitish: ${{ github.sha }}
  257. env:
  258. GITHUB_TOKEN: ${{ steps.committer.outputs.token }}
  259. TAURI_BUNDLER_NEW_APPIMAGE_FORMAT: true
  260. TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
  261. TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
  262. APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
  263. APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
  264. APPLE_SIGNING_IDENTITY: ${{ env.CERT_ID }}
  265. APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
  266. APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
  267. APPLE_API_KEY_PATH: ${{ runner.temp }}/apple-api-key.p8
  268. build-electron:
  269. needs:
  270. - version
  271. continue-on-error: false
  272. strategy:
  273. fail-fast: false
  274. matrix:
  275. settings:
  276. - host: macos-latest
  277. target: x86_64-apple-darwin
  278. platform_flag: --mac --x64
  279. - host: macos-latest
  280. target: aarch64-apple-darwin
  281. platform_flag: --mac --arm64
  282. # github-hosted: blacksmith lacks ARM64 MSVC cross-compilation toolchain
  283. - host: "windows-2025"
  284. target: aarch64-pc-windows-msvc
  285. platform_flag: --win --arm64
  286. - host: "blacksmith-4vcpu-windows-2025"
  287. target: x86_64-pc-windows-msvc
  288. platform_flag: --win
  289. - host: "blacksmith-4vcpu-ubuntu-2404"
  290. target: x86_64-unknown-linux-gnu
  291. platform_flag: --linux
  292. - host: "blacksmith-4vcpu-ubuntu-2404"
  293. target: aarch64-unknown-linux-gnu
  294. platform_flag: --linux
  295. runs-on: ${{ matrix.settings.host }}
  296. # if: github.ref_name == 'beta'
  297. steps:
  298. - uses: actions/checkout@v3
  299. - uses: apple-actions/import-codesign-certs@v2
  300. if: runner.os == 'macOS'
  301. with:
  302. keychain: build
  303. p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }}
  304. p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
  305. - name: Setup Apple API Key
  306. if: runner.os == 'macOS'
  307. run: echo "${{ secrets.APPLE_API_KEY_PATH }}" > $RUNNER_TEMP/apple-api-key.p8
  308. - uses: ./.github/actions/setup-bun
  309. - uses: actions/setup-node@v4
  310. with:
  311. node-version: "24"
  312. - name: Cache apt packages
  313. if: contains(matrix.settings.host, 'ubuntu')
  314. uses: actions/cache@v4
  315. with:
  316. path: ~/apt-cache
  317. key: ${{ runner.os }}-${{ matrix.settings.target }}-apt-electron-${{ hashFiles('.github/workflows/publish.yml') }}
  318. restore-keys: |
  319. ${{ runner.os }}-${{ matrix.settings.target }}-apt-electron-
  320. - name: Install dependencies (ubuntu only)
  321. if: contains(matrix.settings.host, 'ubuntu')
  322. run: |
  323. mkdir -p ~/apt-cache && chmod -R a+rw ~/apt-cache
  324. sudo apt-get update
  325. sudo apt-get install -y --no-install-recommends -o dir::cache::archives="$HOME/apt-cache" rpm
  326. sudo chmod -R a+rw ~/apt-cache
  327. - name: Setup git committer
  328. id: committer
  329. uses: ./.github/actions/setup-git-committer
  330. with:
  331. opencode-app-id: ${{ vars.OPENCODE_APP_ID }}
  332. opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
  333. - name: Prepare
  334. run: bun ./scripts/prepare.ts
  335. working-directory: packages/desktop-electron
  336. env:
  337. OPENCODE_VERSION: ${{ needs.version.outputs.version }}
  338. OPENCODE_CHANNEL: ${{ (github.ref_name == 'beta' && 'beta') || 'prod' }}
  339. RUST_TARGET: ${{ matrix.settings.target }}
  340. GH_TOKEN: ${{ github.token }}
  341. GITHUB_RUN_ID: ${{ github.run_id }}
  342. - name: Build
  343. run: bun run build
  344. working-directory: packages/desktop-electron
  345. env:
  346. OPENCODE_CHANNEL: ${{ (github.ref_name == 'beta' && 'beta') || 'prod' }}
  347. - name: Package and publish
  348. if: needs.version.outputs.release
  349. run: npx electron-builder ${{ matrix.settings.platform_flag }} --publish always --config electron-builder.config.ts
  350. working-directory: packages/desktop-electron
  351. timeout-minutes: 60
  352. env:
  353. OPENCODE_CHANNEL: ${{ (github.ref_name == 'beta' && 'beta') || 'prod' }}
  354. GH_TOKEN: ${{ steps.committer.outputs.token }}
  355. CSC_LINK: ${{ secrets.APPLE_CERTIFICATE }}
  356. CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
  357. APPLE_API_KEY: ${{ runner.temp }}/apple-api-key.p8
  358. APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY }}
  359. APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
  360. - name: Package (no publish)
  361. if: ${{ !needs.version.outputs.release }}
  362. run: npx electron-builder ${{ matrix.settings.platform_flag }} --publish never --config electron-builder.config.ts
  363. working-directory: packages/desktop-electron
  364. timeout-minutes: 60
  365. env:
  366. OPENCODE_CHANNEL: ${{ (github.ref_name == 'beta' && 'beta') || 'prod' }}
  367. - uses: actions/upload-artifact@v4
  368. with:
  369. name: opencode-electron-${{ matrix.settings.target }}
  370. path: packages/desktop-electron/dist/*
  371. - uses: actions/upload-artifact@v4
  372. if: needs.version.outputs.release
  373. with:
  374. name: latest-yml-${{ matrix.settings.target }}
  375. path: packages/desktop-electron/dist/latest*.yml
  376. publish:
  377. needs:
  378. - version
  379. - build-cli-darwin
  380. - build-cli-linux-win
  381. - build-tauri
  382. - build-electron
  383. runs-on: blacksmith-4vcpu-ubuntu-2404
  384. steps:
  385. - uses: actions/checkout@v3
  386. - uses: ./.github/actions/setup-bun
  387. - name: Login to GitHub Container Registry
  388. uses: docker/login-action@v3
  389. with:
  390. registry: ghcr.io
  391. username: ${{ github.repository_owner }}
  392. password: ${{ secrets.GITHUB_TOKEN }}
  393. - name: Set up QEMU
  394. uses: docker/setup-qemu-action@v3
  395. - name: Set up Docker Buildx
  396. uses: docker/setup-buildx-action@v3
  397. - uses: actions/setup-node@v4
  398. with:
  399. node-version: "24"
  400. registry-url: "https://registry.npmjs.org"
  401. - name: Setup git committer
  402. id: committer
  403. uses: ./.github/actions/setup-git-committer
  404. with:
  405. opencode-app-id: ${{ vars.OPENCODE_APP_ID }}
  406. opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
  407. - uses: actions/download-artifact@v4
  408. with:
  409. pattern: opencode-cli-*
  410. path: packages/opencode/dist
  411. merge-multiple: true
  412. - uses: actions/download-artifact@v4
  413. if: needs.version.outputs.release
  414. with:
  415. pattern: latest-yml-*
  416. path: /tmp/latest-yml
  417. - name: Cache apt packages (AUR)
  418. uses: actions/cache@v4
  419. with:
  420. path: /var/cache/apt/archives
  421. key: ${{ runner.os }}-apt-aur-${{ hashFiles('.github/workflows/publish.yml') }}
  422. restore-keys: |
  423. ${{ runner.os }}-apt-aur-
  424. - name: Setup SSH for AUR
  425. run: |
  426. sudo apt-get update
  427. sudo apt-get install -y pacman-package-manager
  428. mkdir -p ~/.ssh
  429. echo "${{ secrets.AUR_KEY }}" > ~/.ssh/id_rsa
  430. chmod 600 ~/.ssh/id_rsa
  431. git config --global user.email "[email protected]"
  432. git config --global user.name "opencode"
  433. ssh-keyscan -H aur.archlinux.org >> ~/.ssh/known_hosts || true
  434. - run: ./script/publish.ts
  435. env:
  436. OPENCODE_VERSION: ${{ needs.version.outputs.version }}
  437. OPENCODE_RELEASE: ${{ needs.version.outputs.release }}
  438. AUR_KEY: ${{ secrets.AUR_KEY }}
  439. GITHUB_TOKEN: ${{ steps.committer.outputs.token }}
  440. GH_REPO: ${{ needs.version.outputs.repo }}
  441. NPM_CONFIG_PROVENANCE: false
  442. LATEST_YML_DIR: /tmp/latest-yml