static.yaml 12 KB

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