static.yaml 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. ---
  2. name: Build binary releases
  3. concurrency:
  4. cancel-in-progress: true
  5. group: ${{ github.workflow }}-${{ github.ref }}
  6. on:
  7. pull_request:
  8. branches:
  9. - main
  10. paths-ignore:
  11. - 'docs/**'
  12. push:
  13. branches:
  14. - main
  15. tags:
  16. - v*.*.*
  17. workflow_dispatch:
  18. inputs:
  19. version:
  20. description: 'FrankenPHP version'
  21. required: false
  22. type: string
  23. schedule:
  24. - cron: '0 0 * * *'
  25. env:
  26. IMAGE_NAME: ${{ (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.version) || startsWith(github.ref, 'refs/tags/')) && 'dunglas/frankenphp' || 'dunglas/frankenphp-dev' }}
  27. jobs:
  28. prepare:
  29. runs-on: ubuntu-latest
  30. outputs:
  31. push: ${{ toJson((steps.check.outputs.ref || (github.event_name == 'workflow_dispatch' && inputs.version) || startsWith(github.ref, 'refs/tags/') || (github.ref == 'refs/heads/main' && github.event_name != 'pull_request')) && true || false) }}
  32. platforms: ${{ steps.matrix.outputs.platforms }}
  33. metadata: ${{ steps.matrix.outputs.metadata }}
  34. ref: ${{ steps.check.outputs.ref }}
  35. steps:
  36. -
  37. name: Get version
  38. id: check
  39. if: github.event_name == 'schedule'
  40. run: |
  41. ref="${{ (github.ref_type == 'tag' && github.ref_name) || (github.event_name == 'workflow_dispatch' && inputs.version) || '' }}"
  42. if [[ -z "${ref}" ]]; then
  43. ref="$(gh release view --repo dunglas/frankenphp --json tagName --jq '.tagName')"
  44. fi
  45. echo "ref=${ref}" >> "${GITHUB_OUTPUT}"
  46. env:
  47. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  48. -
  49. uses: actions/checkout@v4
  50. with:
  51. ref: ${{ steps.check.outputs.ref }}
  52. -
  53. name: Set up Docker Buildx
  54. uses: docker/setup-buildx-action@v3
  55. -
  56. name: Create platforms matrix
  57. id: matrix
  58. run: |
  59. METADATA="$(docker buildx bake --print static-builder | jq -c)"
  60. {
  61. echo metadata="${METADATA}"
  62. echo platforms="$(jq -c 'first(.target[]) | .platforms' <<< "${METADATA}")"
  63. } >> "${GITHUB_OUTPUT}"
  64. env:
  65. SHA: ${{ github.sha }}
  66. VERSION: ${{ steps.check.outputs.ref || 'dev' }}
  67. build-linux:
  68. strategy:
  69. fail-fast: false
  70. matrix:
  71. platform: ${{ fromJson(needs.prepare.outputs.platforms) }}
  72. debug: [false]
  73. mimalloc: [false]
  74. include:
  75. -
  76. qemu: true
  77. -
  78. platform: linux/amd64
  79. qemu: false
  80. -
  81. platform: linux/amd64
  82. qemu: false
  83. debug: true
  84. -
  85. platform: linux/amd64
  86. qemu: false
  87. mimalloc: true
  88. name: Build ${{ matrix.platform }} static binary${{ matrix.debug && ' (debug)' || '' }}${{ matrix.mimalloc && ' (mimalloc)' || '' }}
  89. runs-on: ubuntu-latest
  90. needs: [ prepare ]
  91. steps:
  92. -
  93. uses: actions/checkout@v4
  94. with:
  95. ref: ${{ needs.prepare.outputs.ref }}
  96. -
  97. name: Set up QEMU
  98. if: matrix.qemu
  99. uses: docker/setup-qemu-action@v3
  100. with:
  101. platforms: ${{ matrix.platform }}
  102. -
  103. name: Set up Docker Buildx
  104. uses: docker/setup-buildx-action@v3
  105. with:
  106. platforms: ${{ matrix.platform }}
  107. -
  108. name: Login to DockerHub
  109. if: ${{ fromJson(needs.prepare.outputs.push) && !matrix.debug && !matrix.mimalloc }}
  110. uses: docker/login-action@v3
  111. with:
  112. username: ${{ secrets.REGISTRY_USERNAME }}
  113. password: ${{ secrets.REGISTRY_PASSWORD }}
  114. -
  115. name: Build
  116. id: build
  117. uses: docker/bake-action@v5
  118. with:
  119. pull: true
  120. load: ${{ !fromJson(needs.prepare.outputs.push) || matrix.debug || matrix.mimalloc }}
  121. targets: static-builder
  122. set: |
  123. ${{ matrix.debug && 'static-builder.args.DEBUG_SYMBOLS=1' || '' }}
  124. ${{ matrix.mimalloc && 'static-builder.args.MIMALLOC=1' || '' }}
  125. ${{ matrix.platform == 'linux/arm64' && 'static-builder.args.NO_COMPRESS=1' || '' }}
  126. *.tags=
  127. *.platform=${{ matrix.platform }}
  128. *.cache-from=type=gha,scope=${{ needs.prepare.outputs.ref || github.ref }}-static-builder${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }}
  129. *.cache-from=type=gha,scope=refs/heads/main-static-builder${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }}
  130. *.cache-to=type=gha,scope=${{ needs.prepare.outputs.ref || github.ref }}-static-builder${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }},ignore-error=true
  131. ${{ (fromJson(needs.prepare.outputs.push) && !matrix.debug && !matrix.mimalloc) && format('*.output=type=image,name={0},push-by-digest=true,name-canonical=true,push=true', env.IMAGE_NAME) || '' }}
  132. env:
  133. SHA: ${{ github.sha }}
  134. VERSION: ${{ (github.ref_type == 'tag' && github.ref_name) || needs.prepare.outputs.ref || 'dev' }}
  135. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  136. -
  137. # Workaround for https://github.com/actions/runner/pull/2477#issuecomment-1501003600
  138. name: Export metadata
  139. if: fromJson(needs.prepare.outputs.push) && !matrix.debug && !matrix.mimalloc
  140. run: |
  141. mkdir -p /tmp/metadata
  142. # shellcheck disable=SC2086
  143. digest=$(jq -r '."static-builder"."containerimage.digest"' <<< ${METADATA})
  144. touch "/tmp/metadata/${digest#sha256:}"
  145. env:
  146. METADATA: ${{ steps.build.outputs.metadata }}
  147. -
  148. name: Upload metadata
  149. if: fromJson(needs.prepare.outputs.push) && !matrix.debug && !matrix.mimalloc
  150. uses: actions/upload-artifact@v3
  151. with:
  152. name: metadata-static-builder
  153. path: /tmp/metadata/*
  154. if-no-files-found: error
  155. retention-days: 1
  156. -
  157. name: Copy binary
  158. if: ${{ !fromJson(needs.prepare.outputs.push) || matrix.debug || matrix.mimalloc }}
  159. run: |
  160. digest=$(jq -r '."static-builder"."containerimage.config.digest"' <<< "${METADATA}")
  161. docker create --platform=${{ matrix.platform }} --name static-builder "${digest}"
  162. docker cp "static-builder:/go/src/app/dist/${BINARY}" "${BINARY}${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }}"
  163. env:
  164. METADATA: ${{ steps.build.outputs.metadata }}
  165. BINARY: frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }}
  166. -
  167. name: Upload artifact
  168. if: ${{ !fromJson(needs.prepare.outputs.push) }}
  169. uses: actions/upload-artifact@v3
  170. with:
  171. name: frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }}${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }}
  172. path: frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }}${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }}
  173. -
  174. name: Upload special assets
  175. if: fromJson(needs.prepare.outputs.push) && (matrix.debug || matrix.mimalloc) && (needs.prepare.outputs.ref || github.ref_type == 'tag')
  176. run: gh release upload "${{ (github.ref_type == 'tag' && github.ref_name) || needs.prepare.outputs.ref }}" frankenphp-linux-x86_64${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }} --repo dunglas/frankenphp --clobber
  177. env:
  178. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  179. # Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/
  180. push:
  181. runs-on: ubuntu-latest
  182. needs:
  183. - prepare
  184. - build-linux
  185. if: fromJson(needs.prepare.outputs.push)
  186. steps:
  187. -
  188. name: Download metadata
  189. uses: actions/download-artifact@v3
  190. with:
  191. name: metadata-static-builder
  192. path: /tmp/metadata
  193. -
  194. name: Set up Docker Buildx
  195. uses: docker/setup-buildx-action@v3
  196. -
  197. name: Login to DockerHub
  198. uses: docker/login-action@v3
  199. with:
  200. username: ${{ secrets.REGISTRY_USERNAME }}
  201. password: ${{ secrets.REGISTRY_PASSWORD }}
  202. -
  203. name: Create manifest list and push
  204. working-directory: /tmp/metadata
  205. run: |
  206. # shellcheck disable=SC2046,SC2086
  207. docker buildx imagetools create $(jq -cr '.target."static-builder".tags | map("-t " + .) | join(" ")' <<< "${METADATA}") \
  208. $(printf "${IMAGE_NAME}@sha256:%s " *)
  209. env:
  210. METADATA: ${{ needs.prepare.outputs.metadata }}
  211. -
  212. name: Inspect image
  213. run: |
  214. # shellcheck disable=SC2046,SC2086
  215. docker buildx imagetools inspect "$(jq -cr '.target."static-builder".tags | first' <<< "${METADATA}")"
  216. env:
  217. METADATA: ${{ needs.prepare.outputs.metadata }}
  218. -
  219. name: Copy binary
  220. run: |
  221. tag=$(jq -cr '.target."static-builder".tags | first' <<< "${METADATA}")
  222. docker cp "$(docker create --platform=linux/amd64 --name static-builder "${tag}"):/go/src/app/dist/frankenphp-linux-x86_64" frankenphp-linux-x86_64 ; docker rm static-builder
  223. docker cp "$(docker create --platform=linux/arm64 --name static-builder "${tag}"):/go/src/app/dist/frankenphp-linux-aarch64" frankenphp-linux-aarch64 ; docker rm static-builder
  224. env:
  225. METADATA: ${{ needs.prepare.outputs.metadata }}
  226. -
  227. name: Upload asset
  228. if: needs.prepare.outputs.ref || github.ref_type == 'tag'
  229. run: gh release upload "${{ (github.ref_type == 'tag' && github.ref_name) || needs.prepare.outputs.ref }}" frankenphp-linux-x86_64 frankenphp-linux-aarch64 --repo dunglas/frankenphp --clobber
  230. env:
  231. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  232. build-mac:
  233. strategy:
  234. fail-fast: false
  235. matrix:
  236. platform: ['arm64', 'x86_64']
  237. name: Build macOS ${{ matrix.platform }} binaries
  238. runs-on: ${{ matrix.platform == 'arm64' && 'macos-14' || 'macos-13' }}
  239. needs: [ prepare ]
  240. env:
  241. HOMEBREW_NO_AUTO_UPDATE: 1
  242. steps:
  243. -
  244. uses: actions/checkout@v4
  245. with:
  246. ref: ${{ needs.prepare.outputs.ref }}
  247. -
  248. uses: actions/setup-go@v5
  249. with:
  250. go-version: '1.22'
  251. cache-dependency-path: |
  252. go.sum
  253. caddy/go.sum
  254. -
  255. name: Set FRANKENPHP_VERSION
  256. run: |
  257. if [ "${GITHUB_REF_TYPE}" == "tag" ]; then
  258. export FRANKENPHP_VERSION=${GITHUB_REF_NAME:1}
  259. elif [ "${GITHUB_EVENT_NAME}" == "schedule" ]; then
  260. export FRANKENPHP_VERSION="${{ needs.prepare.outputs.ref }}"
  261. else
  262. export FRANKENPHP_VERSION=${GITHUB_SHA}
  263. fi
  264. echo "FRANKENPHP_VERSION=${FRANKENPHP_VERSION}" >> "${GITHUB_ENV}"
  265. -
  266. name: Build FrankenPHP
  267. run: ./build-static.sh
  268. env:
  269. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  270. RELEASE: ${{ (needs.prepare.outputs.ref || github.ref_type == 'tag') && '1' || '' }}
  271. -
  272. name: Upload artifact
  273. if: github.ref_type == 'branch'
  274. uses: actions/upload-artifact@v3
  275. with:
  276. name: frankenphp-mac-${{ matrix.platform }}
  277. path: dist/frankenphp-mac-${{ matrix.platform }}