Skip to content

Commit 5b03661

Browse files
committed
Build images
1 parent a855c0c commit 5b03661

File tree

6 files changed

+246
-188
lines changed

6 files changed

+246
-188
lines changed

.github/workflows/build.yml

Lines changed: 113 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,90 @@
1-
# This is a GitHub workflow defining a set of jobs with a set of steps.
2-
# ref: https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions
3-
#
4-
# Test build release artifacts (PyPI package, Docker images) and publish them on
5-
# pushed git tags.
6-
#
7-
name: Release
1+
name: Build
82

93
on:
104
pull_request:
115
paths-ignore:
126
- "docs/**"
13-
- "**.md"
14-
- "**.rst"
15-
- ".github/workflows/*"
16-
- "!.github/workflows/release.yml"
177
push:
188
paths-ignore:
199
- "docs/**"
20-
- "**.md"
21-
- "**.rst"
22-
- ".github/workflows/*"
23-
- "!.github/workflows/release.yml"
2410
branches-ignore:
2511
- "dependabot/**"
2612
- "pre-commit-ci-update-config"
27-
tags:
28-
- "**"
2913
workflow_dispatch:
3014

15+
# Tags are calculated based on the existing tags in the repository
16+
# so we can only run builds consecutively, otherwise two images in
17+
# different builds may have the same tag.
18+
# If there are multiple pending jobs older pending jobs will be cancelled.
19+
concurrency:
20+
group: ${{ github.workflow }}-${{ github.ref }}
21+
22+
env:
23+
# If we're on this branch don't bother fetching every tag since we know
24+
# this will be the most recent tag, i.e. builds on this branch should always
25+
# update the `latest` tag
26+
LATEST_BRANCH: main
27+
# Only push images if this workflow is run on this branch
28+
# This ensures if a a new branch is created in this repo it won't automatically
29+
# push an image.
30+
# If this is a backport then change this to the name of the backports branch
31+
PUBLISH_BRANCH: main
32+
33+
# IMAGE: jupyterhub/jupyterhub
34+
IMAGE: manics/jupyterhub-image-test
35+
SINGLEUSER: manics/jupyterhub-singleuser-image-test
36+
PUBLISH_DOCKERIO: "false"
37+
38+
# Enable caching across builds, set to "" to disable
39+
CACHE_FROM: type=gha
40+
CACHE_TO: type=gha,mode=max
41+
3142
jobs:
32-
build-release:
43+
tag:
3344
runs-on: ubuntu-22.04
45+
timeout-minutes: 2
46+
outputs:
47+
existing-tags: ${{ steps.quayio.outputs.tags }}
48+
new-tag: ${{ steps.new.outputs.TAG }}
49+
jupyterhub-version: ${{ steps.version.outputs.VERSION }}
50+
3451
steps:
3552
- uses: actions/checkout@v4
36-
- uses: actions/setup-python@v5
37-
with:
38-
python-version: "3.11"
39-
cache: pip
40-
41-
- uses: actions/setup-node@v4
42-
with:
43-
node-version: "20"
44-
45-
- name: install build requirements
46-
run: |
47-
npm install -g yarn
48-
pip install --upgrade pip
49-
pip install build
50-
pip freeze
51-
52-
- name: build release
53-
run: |
54-
python -m build --sdist --wheel .
55-
ls -l dist
56-
57-
- name: verify sdist
58-
run: |
59-
./ci/check_sdist.py dist/jupyterhub-*.tar.gz
60-
61-
- name: verify data-files are installed where they are found
62-
run: |
63-
pip install dist/*.whl
64-
./ci/check_installed_data.py
6553

66-
- name: verify sdist can be installed without npm/yarn
54+
- name: JupyterHub version
55+
id: version
6756
run: |
68-
docker run --rm -v $PWD/dist:/dist:ro docker.io/library/python:3.9-slim-bullseye bash -c 'pip install /dist/jupyterhub-*.tar.gz'
57+
VERSION=$(grep '^jupyterhub==' base/requirements.txt | cut -d= -f3)
58+
if [[ $VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then
59+
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
60+
else
61+
echo "Failed to get JupyterHub version"
62+
exit 1
63+
fi
6964
70-
# ref: https://github.com/actions/upload-artifact#readme
71-
- uses: actions/upload-artifact@v4
65+
- name: Get build-number by looking at existing tags
66+
id: quayio
67+
uses: manics/action-get-quayio-tags@main
7268
with:
73-
name: jupyterhub-${{ github.sha }}
74-
path: "dist/*"
75-
if-no-files-found: error
76-
77-
- name: Publish to PyPI
78-
if: startsWith(github.ref, 'refs/tags/')
79-
env:
80-
TWINE_USERNAME: __token__
81-
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
69+
repository: ${{ env.IMAGE }}
70+
version: ${{ steps.version.outputs.VERSION }}
71+
# https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#github-context
72+
# If this is not LATEST_BRANCH, nor is it a pull request against LATEST_BRANCH
73+
# assume it's a backport branch which means we need to get all tags to work out
74+
# which MAJOR and MAJOR.MINOR aliases are needed.
75+
allTags: ${{ (github.ref != format('refs/heads/{0}', env.LATEST_BRANCH)) && (github.base_ref != format('refs/heads/{0}', env.LATEST_BRANCH)) }}
76+
strict: "true"
77+
78+
- name: Get new tag
79+
id: new
8280
run: |
83-
pip install twine
84-
twine upload --skip-existing dist/*
81+
echo "TAG=${{ steps.version.outputs.VERSION }}-${{ steps.quayio.outputs.buildNumber }}" >> $GITHUB_OUTPUT
8582
8683
publish-docker:
8784
runs-on: ubuntu-22.04
8885
timeout-minutes: 30
86+
needs:
87+
- tag
8988

9089
services:
9190
# So that we can test this in PRs/branches
@@ -95,19 +94,23 @@ jobs:
9594
- 5000:5000
9695

9796
steps:
97+
- uses: actions/checkout@v4
98+
9899
- name: Should we push this image to a public registry?
99100
run: |
100-
if [ "${{ startsWith(github.ref, 'refs/tags/') || (github.ref == 'refs/heads/main') }}" = "true" ]; then
101+
if [ "${{ github.ref == format('refs/heads/{0}', env.PUBLISH_BRANCH) }}" = "true" ]; then
101102
echo "REGISTRY=quay.io/" >> $GITHUB_ENV
103+
echo "PUBLIC=true" >> $GITHUB_ENV
102104
else
103105
echo "REGISTRY=localhost:5000/" >> $GITHUB_ENV
106+
echo "PUBLIC=false" >> $GITHUB_ENV
104107
fi
105108
106109
- uses: actions/checkout@v4
107110

108111
# Setup docker to build for multiple platforms, see:
109-
# https://github.com/docker/build-push-action/tree/v2.4.0#usage
110-
# https://github.com/docker/build-push-action/blob/v2.4.0/docs/advanced/multi-platform.md
112+
# https://github.com/docker/build-push-action/tree/v6.9.0?tab=readme-ov-file#usage
113+
# https://docs.docker.com/build/ci/github-actions/multi-platform/
111114
- name: Set up QEMU (for docker buildx)
112115
uses: docker/setup-qemu-action@v3
113116

@@ -123,53 +126,59 @@ jobs:
123126
# . Quay.io org
124127
# 2. Giving it enough permissions to push to the jupyterhub and singleuser images
125128
# 3. Putting the robot account's username and password in GitHub actions environment
126-
if: env.REGISTRY != 'localhost:5000/'
129+
if: env.PUBLIC == 'true'
127130
run: |
128131
docker login -u "${{ secrets.QUAY_USERNAME }}" -p "${{ secrets.QUAY_PASSWORD }}" "${{ env.REGISTRY }}"
129-
docker login -u "${{ secrets.DOCKERHUB_USERNAME }}" -p "${{ secrets.DOCKERHUB_TOKEN }}" docker.io
132+
if [ "${{ env.PUBLISH_DOCKERIO }}" = "true" ]; then
133+
docker login -u "${{ secrets.DOCKERHUB_USERNAME }}" -p "${{ secrets.DOCKERHUB_TOKEN }}" docker.io
134+
fi
130135
131-
# image: jupyterhub/jupyterhub
136+
# image: env.IMAGE
132137
#
133138
# https://github.com/jupyterhub/action-major-minor-tag-calculator
134139
# If this is a tagged build this will return additional parent tags.
135140
# E.g. 1.2.3 is expanded to Docker tags
136141
# [{prefix}:1.2.3, {prefix}:1.2, {prefix}:1, {prefix}:latest] unless
137142
# this is a backported tag in which case the newer tags aren't updated.
138-
# For branches this will return the branch name.
139-
# If GITHUB_TOKEN isn't available (e.g. in PRs) returns no tags [].
140-
- name: Get list of jupyterhub tags
143+
- name: Calculate tags
141144
id: jupyterhubtags
142-
uses: jupyterhub/action-major-minor-tag-calculator@v3
145+
uses: manics/action-major-minor-tag-calculator@allow-external-tag
143146
with:
144-
githubToken: ${{ secrets.GITHUB_TOKEN }}
147+
tagList: ${{ needs.tag.outputs.existing-tags }}
148+
currentTag: ${{ needs.tag.outputs.new-tag }}
145149
prefix: >-
146-
${{ env.REGISTRY }}jupyterhub/jupyterhub:
147-
jupyterhub/jupyterhub:
148-
defaultTag: "${{ env.REGISTRY }}jupyterhub/jupyterhub:noref"
149-
branchRegex: ^\w[\w-.]*$
150+
${{ env.REGISTRY }}${{ env.IMAGE }}:
151+
${{ (env.PUBLIC == 'true' && env.PUBLISH_DOCKERIO == 'true') && format('{0}:', env.IMAGE) || '' }}
152+
153+
- name: Print tags
154+
run: |
155+
echo "Existing tags: ${{ needs.tag.outputs.existing-tags }}"
156+
echo "New tags: ${{ needs.tag.outputs.new-tag }}"
157+
echo "Image tags: ${{ steps.jupyterhubtags.outputs.tags }}"
150158
151159
- name: Build and push jupyterhub
152160
uses: docker/build-push-action@v6
153161
with:
154-
context: .
162+
context: base
155163
platforms: linux/amd64,linux/arm64
156164
push: true
157165
# tags parameter must be a string input so convert `gettags` JSON
158166
# array into a comma separated list of tags
159167
tags: ${{ join(fromJson(steps.jupyterhubtags.outputs.tags)) }}
168+
cache-from: ${{ env.CACHE_FROM }}
169+
cache-to: ${{ env.CACHE_TO }}
160170

161-
# image: jupyterhub/jupyterhub-onbuild
171+
# image: env.IMAGE-onbuild
162172
#
163173
- name: Get list of jupyterhub-onbuild tags
164174
id: onbuildtags
165-
uses: jupyterhub/action-major-minor-tag-calculator@v3
175+
uses: manics/action-major-minor-tag-calculator@allow-external-tag
166176
with:
167-
githubToken: ${{ secrets.GITHUB_TOKEN }}
177+
tagList: ${{ needs.tag.outputs.existing-tags }}
178+
currentTag: ${{ needs.tag.outputs.new-tag }}
168179
prefix: >-
169-
${{ env.REGISTRY }}jupyterhub/jupyterhub-onbuild:
170-
jupyterhub/jupyterhub-onbuild:
171-
defaultTag: "${{ env.REGISTRY }}jupyterhub/jupyterhub-onbuild:noref"
172-
branchRegex: ^\w[\w-.]*$
180+
${{ env.REGISTRY }}${{ env.IMAGE }}-onbuild:
181+
${{ (env.PUBLIC == 'true' && env.PUBLISH_DOCKERIO == 'true') && format('{0}-onbuild:', env.IMAGE) || '' }}
173182
174183
- name: Build and push jupyterhub-onbuild
175184
uses: docker/build-push-action@v6
@@ -180,19 +189,20 @@ jobs:
180189
platforms: linux/amd64,linux/arm64
181190
push: true
182191
tags: ${{ join(fromJson(steps.onbuildtags.outputs.tags)) }}
192+
cache-from: ${{ env.CACHE_FROM }}
193+
cache-to: ${{ env.CACHE_TO }}
183194

184-
# image: jupyterhub/jupyterhub-demo
195+
# image: env.IMAGE-demo
185196
#
186197
- name: Get list of jupyterhub-demo tags
187198
id: demotags
188-
uses: jupyterhub/action-major-minor-tag-calculator@v3
199+
uses: manics/action-major-minor-tag-calculator@allow-external-tag
189200
with:
190-
githubToken: ${{ secrets.GITHUB_TOKEN }}
201+
tagList: ${{ needs.tag.outputs.existing-tags }}
202+
currentTag: ${{ needs.tag.outputs.new-tag }}
191203
prefix: >-
192-
${{ env.REGISTRY }}jupyterhub/jupyterhub-demo:
193-
jupyterhub/jupyterhub-demo:
194-
defaultTag: "${{ env.REGISTRY }}jupyterhub/jupyterhub-demo:noref"
195-
branchRegex: ^\w[\w-.]*$
204+
${{ env.REGISTRY }}${{ env.IMAGE }}-demo:
205+
${{ (env.PUBLIC == 'true' && env.PUBLISH_DOCKERIO == 'true') && format('{0}-demo:', env.IMAGE) || '' }}
196206
197207
- name: Build and push jupyterhub-demo
198208
uses: docker/build-push-action@v6
@@ -206,26 +216,29 @@ jobs:
206216
platforms: linux/amd64
207217
push: true
208218
tags: ${{ join(fromJson(steps.demotags.outputs.tags)) }}
219+
cache-from: ${{ env.CACHE_FROM }}
220+
cache-to: ${{ env.CACHE_TO }}
209221

210-
# image: jupyterhub/singleuser
222+
# image: env.SINGLEUSER
211223
#
212224
- name: Get list of jupyterhub/singleuser tags
213225
id: singleusertags
214-
uses: jupyterhub/action-major-minor-tag-calculator@v3
226+
uses: manics/action-major-minor-tag-calculator@allow-external-tag
215227
with:
216-
githubToken: ${{ secrets.GITHUB_TOKEN }}
228+
tagList: ${{ needs.tag.outputs.existing-tags }}
229+
currentTag: ${{ needs.tag.outputs.new-tag }}
217230
prefix: >-
218-
${{ env.REGISTRY }}jupyterhub/singleuser:
219-
jupyterhub/singleuser:
220-
defaultTag: "${{ env.REGISTRY }}jupyterhub/singleuser:noref"
221-
branchRegex: ^\w[\w-.]*$
231+
${{ env.REGISTRY }}${{ env.SINGLEUSER }}:
232+
${{ (env.PUBLIC == 'true' && env.PUBLISH_DOCKERIO == 'true') && format('{0}:', env.SINGLEUSER) || '' }}
222233
223234
- name: Build and push jupyterhub/singleuser
224235
uses: docker/build-push-action@v6
225236
with:
226237
build-args: |
227-
JUPYTERHUB_VERSION=${{ github.ref_type == 'tag' && github.ref_name || format('git:{0}', github.sha) }}
238+
JUPYTERHUB_VERSION=${{ needs.tag.outputs.jupyterhub-version }}
228239
context: singleuser
229240
platforms: linux/amd64,linux/arm64
230241
push: true
231242
tags: ${{ join(fromJson(steps.singleusertags.outputs.tags)) }}
243+
cache-from: ${{ env.CACHE_FROM }}
244+
cache-to: ${{ env.CACHE_TO }}

0 commit comments

Comments
 (0)