1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
test:
name: Test
runs-on: ubuntu-latest
permissions:
contents: read # checkout
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: ruby/setup-ruby@bec3f19a76460dbe12f60def7d1a77585f07516c # v1
with:
bundler-cache: true
- run: bundle exec rake
zizmor:
name: Audit workflows
runs-on: ubuntu-latest
permissions:
contents: read # checkout
security-events: write # upload SARIF to code scanning
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: zizmorcore/zizmor-action@cc914d7f3750a2d13d75c7f184a1060aa0e9d482 # v0.6.4
build:
name: Build
needs: test
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
permissions:
contents: write # create GitHub release
packages: write # push container image to GHCR
outputs:
version: ${{ steps.meta.outputs.version }}
image: ghcr.io/${{ github.repository }}:${{ steps.meta.outputs.version }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: short-sha
run: echo "sha=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
- uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
id: meta
with:
images: ghcr.io/${{ github.repository }}
flavor: latest=true
tags: |
type=raw,value={{date 'YYYYMMDD-HHmm'}}-${{ steps.short-sha.outputs.sha }}
- uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
VERSION=${{ steps.meta.outputs.version }}
cache-from: type=gha
cache-to: type=gha,mode=max
- env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
STEPS_META_OUTPUTS_VERSION: ${{ steps.meta.outputs.version }}
# --target names the commit explicitly: persist-credentials is
# false, so the tag cannot ride the leftover git credentials.
run: gh release create "${STEPS_META_OUTPUTS_VERSION}" --target "$GITHUB_SHA" --generate-notes
# The release again, on Ruby HEAD with ZJIT on, tagged
# <release>-ruby-head-zjit and ruby-head-zjit. A job of its own so a
# HEAD that will not build or install the bundle holds up neither the
# release nor the deploy.
build-head:
name: Build on Ruby HEAD with ZJIT
needs: build
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
permissions:
contents: read # checkout
packages: write # push container image to GHCR
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
id: meta
with:
images: ghcr.io/${{ github.repository }}
flavor: latest=false
tags: |
type=raw,value=${{ needs.build.outputs.version }}-ruby-head-zjit
type=raw,value=ruby-head-zjit
- uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: .
# Pulled fresh each time: HEAD is the point, so a cached base
# would be yesterday's Ruby.
pull: true
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
RUBY_IMAGE=rubylang/ruby:master-noble
RUBYOPT=--zjit
VERSION=${{ needs.build.outputs.version }}-ruby-head-zjit
cache-from: type=gha,scope=ruby-head-zjit
cache-to: type=gha,scope=ruby-head-zjit,mode=max
deploy:
name: Deploy main preview
needs: build
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
permissions:
contents: read # checkout, for fly.toml
environment:
name: demo
url: https://pro-tacts.fly.dev
# One deploy at a time, and a newer main is the one worth having.
concurrency:
group: fly-deploy
cancel-in-progress: true
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
FLY_APP: pro-tacts
FLY_ORG: personal
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: superfly/flyctl-actions/setup-flyctl@ed8efb33836e8b2096c7fd3ba1c8afe303ebbff1 # 1.6
# Created here rather than by hand, so the app is something this
# repository can lose and get back. `status` is how the review-app
# action asks the same question.
- name: Create the app if it is not there yet
run: flyctl status --app "$FLY_APP" >/dev/null 2>&1 || flyctl apps create "$FLY_APP" --org "$FLY_ORG"
# The image the build job just pushed, rather than a second build
# of the same commit: what the demo runs is then the release.
- name: Deploy the released image
env:
NEEDS_BUILD_OUTPUTS_IMAGE: ${{ needs.build.outputs.image }}
run: flyctl deploy --app "$FLY_APP" --config fly.toml --image "$NEEDS_BUILD_OUTPUTS_IMAGE"