dev.yml 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. name: Dev build (binaries + docker)
  2. on:
  3. push:
  4. branches: [dev]
  5. workflow_dispatch:
  6. concurrency:
  7. group: dev-build-${{ github.ref }}
  8. cancel-in-progress: true
  9. permissions:
  10. contents: write
  11. packages: write
  12. actions: read
  13. env:
  14. RELEASE_TAG: dev-latest
  15. IMAGE: ghcr.io/${{ github.repository }}
  16. jobs:
  17. build-binaries:
  18. name: Build binaries (${{ matrix.name }})
  19. runs-on: ${{ matrix.os }}
  20. strategy:
  21. fail-fast: false
  22. matrix:
  23. include:
  24. - name: linux-x86_64
  25. os: ubuntu-latest
  26. target: x86_64-unknown-linux-gnu
  27. bin: rathole
  28. - name: windows-x86_64
  29. os: windows-latest
  30. target: x86_64-pc-windows-msvc
  31. bin: rathole.exe
  32. - name: macos-x86_64
  33. os: macos-15-intel
  34. target: x86_64-apple-darwin
  35. bin: rathole
  36. - name: macos-arm64
  37. os: macos-15
  38. target: aarch64-apple-darwin
  39. bin: rathole
  40. steps:
  41. - uses: actions/checkout@v4
  42. - uses: actions-rust-lang/setup-rust-toolchain@v1
  43. with:
  44. target: ${{ matrix.target }}
  45. rustflags: ""
  46. - name: Build
  47. shell: bash
  48. run: |
  49. set -euxo pipefail
  50. cargo build --release --locked --bin rathole
  51. - name: Package
  52. shell: bash
  53. run: |
  54. set -euxo pipefail
  55. mkdir -p out dist
  56. cp "target/release/${{ matrix.bin }}" dist/
  57. tar -czf "out/rathole-dev-${{ matrix.target }}.tar.gz" -C dist .
  58. ls -lah out/
  59. - uses: actions/upload-artifact@v4
  60. with:
  61. name: bin-${{ matrix.target }}
  62. path: out/rathole-dev-${{ matrix.target }}.tar.gz
  63. if-no-files-found: error
  64. docker:
  65. name: Build & push docker (dev)
  66. runs-on: ubuntu-latest
  67. outputs:
  68. digest: ${{ steps.build.outputs.digest }}
  69. steps:
  70. - uses: actions/checkout@v4
  71. - uses: docker/setup-qemu-action@v3
  72. - uses: docker/setup-buildx-action@v3
  73. - uses: docker/login-action@v3
  74. with:
  75. registry: ghcr.io
  76. username: ${{ github.actor }}
  77. password: ${{ secrets.GITHUB_TOKEN }}
  78. - name: Docker metadata
  79. id: meta
  80. uses: docker/metadata-action@v5
  81. with:
  82. images: ${{ env.IMAGE }}
  83. tags: |
  84. type=raw,value=dev
  85. type=sha,format=short,prefix=dev-
  86. - name: Build & push
  87. id: build
  88. uses: docker/build-push-action@v6
  89. with:
  90. context: .
  91. file: ./Dockerfile
  92. platforms: linux/amd64,linux/arm64
  93. push: true
  94. tags: ${{ steps.meta.outputs.tags }}
  95. labels: ${{ steps.meta.outputs.labels }}
  96. cache-from: type=gha
  97. cache-to: type=gha,mode=max
  98. release:
  99. name: Update rolling dev release
  100. runs-on: ubuntu-latest
  101. needs: [build-binaries, docker]
  102. steps:
  103. - uses: actions/checkout@v4
  104. with:
  105. fetch-depth: 0
  106. - name: Fetch tags
  107. shell: bash
  108. run: git fetch --tags --force
  109. - name: Remember previous dev tag (if exists)
  110. id: prev
  111. shell: bash
  112. run: |
  113. set -e
  114. if git rev-parse -q --verify "refs/tags/${RELEASE_TAG}" >/dev/null; then
  115. echo "sha=$(git rev-parse refs/tags/${RELEASE_TAG})" >> $GITHUB_OUTPUT
  116. else
  117. echo "sha=" >> $GITHUB_OUTPUT
  118. fi
  119. - name: Move dev tag to this commit (and update prev tag)
  120. shell: bash
  121. run: |
  122. set -euxo pipefail
  123. PREV_TAG="${RELEASE_TAG}-prev"
  124. OLD_SHA="${{ steps.prev.outputs.sha }}"
  125. if [[ -n "${OLD_SHA}" ]]; then
  126. git tag -f "${PREV_TAG}" "${OLD_SHA}"
  127. if ! git push -f origin "refs/tags/${PREV_TAG}" 2>push_prev.err; then
  128. if grep -q "refusing to allow a GitHub App to create or update workflow" push_prev.err; then
  129. echo "::warning::Could not update ${PREV_TAG} because ${OLD_SHA} modifies .github/workflows/. Continuing without previous_tag_name this run."
  130. # Remove the local tag so later steps don't mistakenly think it exists remotely
  131. git tag -d "${PREV_TAG}" || true
  132. else
  133. echo "Unexpected failure pushing ${PREV_TAG}:"
  134. cat push_prev.err
  135. exit 1
  136. fi
  137. fi
  138. fi
  139. git tag -f "${RELEASE_TAG}" "${GITHUB_SHA}"
  140. git push -f origin "refs/tags/${RELEASE_TAG}"
  141. - name: Download artifacts
  142. uses: actions/download-artifact@v4
  143. with:
  144. path: dist
  145. pattern: "bin-*"
  146. merge-multiple: true
  147. - name: Generate PR-based notes + Update Release + upload assets
  148. env:
  149. GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  150. DOCKER_DIGEST: ${{ needs.docker.outputs.digest }}
  151. shell: bash
  152. run: |
  153. set -euxo pipefail
  154. SHORT_SHA="${GITHUB_SHA::7}"
  155. IMAGE="ghcr.io/${GITHUB_REPOSITORY}"
  156. PREV_TAG="${RELEASE_TAG}-prev"
  157. ARGS=(-f tag_name="${RELEASE_TAG}" -f target_commitish="${GITHUB_SHA}")
  158. if git ls-remote --tags origin "refs/tags/${PREV_TAG}" | grep -q .; then
  159. ARGS+=(-f previous_tag_name="${PREV_TAG}")
  160. fi
  161. GEN_NOTES="$(gh api \
  162. -H "Accept: application/vnd.github+json" \
  163. "repos/${GITHUB_REPOSITORY}/releases/generate-notes" \
  164. "${ARGS[@]}" \
  165. --jq '.body'
  166. )"
  167. cat > RELEASE_NOTES.md <<EOF
  168. Automated build from branch \`dev\`.
  169. - Commit: \`${GITHUB_SHA}\`
  170. - Docker:
  171. - \`${IMAGE}:dev\` (moving)
  172. - \`${IMAGE}:dev-${SHORT_SHA}\` (pinned tag)
  173. - \`${IMAGE}@${DOCKER_DIGEST}\` (pinned digest)
  174. Pull:
  175. \`\`\`bash
  176. docker pull ${IMAGE}:dev
  177. docker pull ${IMAGE}:dev-${SHORT_SHA}
  178. docker pull ${IMAGE}@${DOCKER_DIGEST}
  179. \`\`\`
  180. ---
  181. ${GEN_NOTES}
  182. EOF
  183. TITLE="Dev build (${SHORT_SHA})"
  184. if gh release view "${RELEASE_TAG}" >/dev/null 2>&1; then
  185. gh release edit "${RELEASE_TAG}" \
  186. --prerelease \
  187. --title "${TITLE}" \
  188. --notes-file RELEASE_NOTES.md
  189. else
  190. gh release create "${RELEASE_TAG}" \
  191. --prerelease \
  192. --title "${TITLE}" \
  193. --notes-file RELEASE_NOTES.md
  194. fi
  195. mapfile -t FILES < <(find dist -type f -name '*.tar.gz' -print)
  196. if (( ${#FILES[@]} == 0 )); then
  197. echo "No *.tar.gz artifacts found under dist/"
  198. find dist -maxdepth 3 -type f -print || true
  199. exit 1
  200. fi
  201. gh release upload "${RELEASE_TAG}" "${FILES[@]}" --clobber