Skip to content

Commit 5e9bfa5

Browse files
authored
Merge pull request #282 from clamsproject/develop
releasing 1.5.0
2 parents de02c8d + 34852f6 commit 5e9bfa5

21 files changed

Lines changed: 304 additions & 105 deletions

.github/workflows/container.yml

Lines changed: 104 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ on:
1111
required: true
1212
type: string
1313
description: 'name of the container build file to use'
14+
ref:
15+
required: false
16+
type: string
17+
description: 'git ref to checkout (defaults to version)'
1418
workflow_dispatch:
1519
inputs:
1620
version:
@@ -21,30 +25,45 @@ on:
2125
required: true
2226
type: string
2327
description: 'name of the container build file to use'
28+
ref:
29+
required: false
30+
type: string
31+
description: 'git ref to checkout (defaults to version)'
2432

2533
env:
2634
REGISTRY: ghcr.io
2735

2836
jobs:
29-
build-and-push-image:
30-
name: "🐳 Build and push image"
31-
runs-on: ubuntu-latest
37+
build:
38+
name: "🐳 Build (${{ matrix.platform }})"
39+
runs-on: ${{ matrix.runner }}
40+
strategy:
41+
fail-fast: false
42+
matrix:
43+
include:
44+
- platform: linux/amd64
45+
runner: ubuntu-latest
46+
- platform: linux/arm64
47+
runner: ubuntu-24.04-arm
3248
permissions:
3349
contents: read
3450
packages: write
3551

3652
steps:
53+
- name: "🔧 Prepare"
54+
id: prepare
55+
run: |
56+
platform=${{ matrix.platform }}
57+
echo "pair=${platform//\//-}" >> $GITHUB_OUTPUT
58+
slug=$(echo "${{ inputs.buildfilename }}" | sed 's|[^a-zA-Z0-9]|-|g; s/^-*//; s/-*$//')
59+
echo "slug=${slug}" >> $GITHUB_OUTPUT
60+
3761
- name: "🛍️ Checkout repository"
3862
uses: actions/checkout@v4
3963
with:
40-
ref: ${{ inputs.version }}
41-
fetch-depth: 0
42-
43-
- name: "🎛 Set up QEMU"
44-
uses: docker/setup-qemu-action@v3
64+
ref: ${{ inputs.ref || inputs.version }}
4565

4666
- name: "👷 Set up Docker Buildx"
47-
id: buildx
4867
uses: docker/setup-buildx-action@v3
4968

5069
- name: "🏷 Prepare OCI annotations"
@@ -68,23 +87,11 @@ jobs:
6887
export nameonly="${filename%.*}"
6988
if [ ${nameonly} == ${filename} ]; then echo "SUFFIX=" >> $GITHUB_ENV ; else echo "SUFFIX=-${nameonly}" >> $GITHUB_ENV; fi
7089
71-
- name: "🏷 Get SDK version from latest tag"
72-
id: sdkversion
73-
run: |
74-
export version=$(git describe --tags --abbrev=0)
75-
echo "CLAMS_VERSION=${version}" >> $GITHUB_OUTPUT
76-
77-
- name: "🏷 Prepare docker tags, labels"
90+
- name: "🏷 Prepare docker labels"
7891
id: meta
7992
uses: docker/metadata-action@v5
80-
env:
81-
CLAMS_VERSION: ${{ steps.sdkversion.outputs.CLAMS_VERSION }}
8293
with:
8394
images: ${{ env.REGISTRY }}/${{ github.repository }}${{ env.SUFFIX }}
84-
tags: |
85-
type=pep440,pattern={{version}},value=${{ env.CLAMS_VERSION }}
86-
type=ref,event=tag
87-
type=ref,event=pr
8895
labels: |
8996
${{ env.EXISTING_LABELS }}
9097
@@ -95,18 +102,84 @@ jobs:
95102
username: ${{ github.actor }}
96103
password: ${{ secrets.GITHUB_TOKEN }}
97104

98-
- name: "🏗 Build and push image"
99-
uses: docker/build-push-action@v5
100-
env:
101-
CLAMS_VERSION: ${{ steps.sdkversion.outputs.CLAMS_VERSION }}
105+
- name: "🏗 Build and push by digest"
106+
id: build
107+
uses: docker/build-push-action@v6
102108
with:
103109
context: ${{ env.CONTEXT }}
104-
platforms: linux/amd64,linux/arm64
110+
platforms: ${{ matrix.platform }}
105111
file: ${{ inputs.buildfilename }}
106-
tags: ${{ steps.meta.outputs.tags }}
107-
# using {{ steps.meta.outputs.labels }} doesn't work with multi-line variable ($EXISTING_LABLES)
108112
labels: ${{ env.DOCKER_METADATA_OUTPUT_LABELS }}
109113
build-args: |
110-
clams_version=${{ env.CLAMS_VERSION }}
111-
push: true
114+
clams_version=${{ inputs.version }}
115+
outputs: type=image,"name=${{ env.REGISTRY }}/${{ github.repository }}${{ env.SUFFIX }}",push-by-digest=true,name-canonical=true,push=true
116+
117+
- name: "📤 Export digest"
118+
run: |
119+
mkdir -p /tmp/digests
120+
digest="${{ steps.build.outputs.digest }}"
121+
touch "/tmp/digests/${digest#sha256:}"
112122
123+
- name: "📦 Upload digest"
124+
uses: actions/upload-artifact@v4
125+
with:
126+
name: digests-${{ steps.prepare.outputs.slug }}-${{ steps.prepare.outputs.pair }}
127+
path: /tmp/digests/*
128+
if-no-files-found: error
129+
retention-days: 1
130+
131+
merge:
132+
name: "🔗 Create multi-platform manifest"
133+
runs-on: ubuntu-latest
134+
needs: build
135+
permissions:
136+
contents: read
137+
packages: write
138+
139+
steps:
140+
- name: "🔧 Prepare"
141+
id: prepare
142+
run: |
143+
slug=$(echo "${{ inputs.buildfilename }}" | sed 's|[^a-zA-Z0-9]|-|g; s/^-*//; s/-*$//')
144+
echo "slug=${slug}" >> $GITHUB_OUTPUT
145+
146+
- name: "🏷 Get image name suffix"
147+
id: getsuffix
148+
run: |
149+
export filename=$(basename ${{ inputs.buildfilename }})
150+
export nameonly="${filename%.*}"
151+
if [ ${nameonly} == ${filename} ]; then echo "SUFFIX=" >> $GITHUB_ENV ; else echo "SUFFIX=-${nameonly}" >> $GITHUB_ENV; fi
152+
153+
- name: "📥 Download digests"
154+
uses: actions/download-artifact@v4
155+
with:
156+
path: /tmp/digests
157+
pattern: digests-${{ steps.prepare.outputs.slug }}-*
158+
merge-multiple: true
159+
160+
- name: "👷 Set up Docker Buildx"
161+
uses: docker/setup-buildx-action@v3
162+
163+
- name: "🏷 Prepare docker tags"
164+
id: meta
165+
uses: docker/metadata-action@v5
166+
with:
167+
images: ${{ env.REGISTRY }}/${{ github.repository }}${{ env.SUFFIX }}
168+
tags: |
169+
type=pep440,pattern={{version}},value=${{ inputs.version }}
170+
type=ref,event=tag
171+
type=ref,event=pr
172+
173+
- name: "🔏 Log in to registry"
174+
uses: docker/login-action@v3
175+
with:
176+
registry: ${{ env.REGISTRY }}
177+
username: ${{ github.actor }}
178+
password: ${{ secrets.GITHUB_TOKEN }}
179+
180+
- name: "🔗 Create manifest list and push"
181+
working-directory: /tmp/digests
182+
run: |
183+
docker buildx imagetools create \
184+
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
185+
$(printf '${{ env.REGISTRY }}/${{ github.repository }}${{ env.SUFFIX }}@sha256:%s ' *)

.github/workflows/containers.yml

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,15 @@ jobs:
116116
buildfilename: './container/opencv4.containerfile'
117117
version: ${{ needs.set-version.outputs.version }}
118118

119+
call-build-hf:
120+
name: "🤙 Call container workflow with `hf`"
121+
needs: ['set-version', 'call-build-hf5']
122+
uses: ./.github/workflows/container.yml
123+
secrets: inherit
124+
with:
125+
buildfilename: './container/hf.containerfile'
126+
version: ${{ needs.set-version.outputs.version }}
127+
119128
call-build-opencv4-tf2:
120129
name: "🤙 Call container workflow with `opencv4-tf2`"
121130
needs: ['set-version', 'call-build-opencv4']
@@ -134,56 +143,74 @@ jobs:
134143
buildfilename: './container/opencv4-torch2.containerfile'
135144
version: ${{ needs.set-version.outputs.version }}
136145

137-
call-build-tf2-hf:
138-
name: "🤙 Call container workflow with `tf2-hf`"
139-
needs: ['set-version', 'call-build-tf2']
146+
call-build-hf4:
147+
name: "🤙 Call container workflow with `hf4`"
148+
needs: ['set-version', 'call-build-torch2']
140149
uses: ./.github/workflows/container.yml
141150
secrets: inherit
142151
with:
143-
buildfilename: './container/tf2-hf.containerfile'
152+
buildfilename: './container/hf4.containerfile'
144153
version: ${{ needs.set-version.outputs.version }}
145154

146-
call-build-hf:
147-
name: "🤙 Call container workflow with `hf`"
155+
call-build-hf5:
156+
name: "🤙 Call container workflow with `hf5`"
148157
needs: ['set-version', 'call-build-torch2']
149158
uses: ./.github/workflows/container.yml
150159
secrets: inherit
151160
with:
152-
buildfilename: './container/hf.containerfile'
161+
buildfilename: './container/hf5.containerfile'
153162
version: ${{ needs.set-version.outputs.version }}
154163

155-
call-build-ffmpeg-tf2-hf:
156-
name: "🤙 Call container workflow with `ffmpeg-tf2-hf`"
157-
needs: ['set-version', 'call-build-ffmpeg-tf2']
164+
call-build-ffmpeg-hf:
165+
name: "🤙 Call container workflow with `ffmpeg-hf`"
166+
needs: ['set-version', 'call-build-ffmpeg-hf5']
158167
uses: ./.github/workflows/container.yml
159168
secrets: inherit
160169
with:
161-
buildfilename: './container/ffmpeg-tf2-hf.containerfile'
170+
buildfilename: './container/ffmpeg-hf.containerfile'
162171
version: ${{ needs.set-version.outputs.version }}
163172

164-
call-build-ffmpeg-hf:
165-
name: "🤙 Call container workflow with `ffmpeg-hf`"
173+
call-build-ffmpeg-hf4:
174+
name: "🤙 Call container workflow with `ffmpeg-hf4`"
166175
needs: ['set-version', 'call-build-ffmpeg-torch2']
167176
uses: ./.github/workflows/container.yml
168177
secrets: inherit
169178
with:
170-
buildfilename: './container/ffmpeg-hf.containerfile'
179+
buildfilename: './container/ffmpeg-hf4.containerfile'
171180
version: ${{ needs.set-version.outputs.version }}
172181

173-
call-build-opencv4-tf2-hf:
174-
name: "🤙 Call container workflow with `opencv4-tf2-hf`"
175-
needs: ['set-version', 'call-build-opencv4-tf2']
182+
call-build-ffmpeg-hf5:
183+
name: "🤙 Call container workflow with `ffmpeg-hf5`"
184+
needs: ['set-version', 'call-build-ffmpeg-torch2']
176185
uses: ./.github/workflows/container.yml
177186
secrets: inherit
178187
with:
179-
buildfilename: './container/opencv4-tf2-hf.containerfile'
188+
buildfilename: './container/ffmpeg-hf5.containerfile'
180189
version: ${{ needs.set-version.outputs.version }}
181190

182191
call-build-opencv4-hf:
183192
name: "🤙 Call container workflow with `opencv4-hf`"
184-
needs: ['set-version', 'call-build-opencv4-torch2']
193+
needs: ['set-version', 'call-build-opencv4-hf5']
185194
uses: ./.github/workflows/container.yml
186195
secrets: inherit
187196
with:
188197
buildfilename: './container/opencv4-hf.containerfile'
189198
version: ${{ needs.set-version.outputs.version }}
199+
200+
call-build-opencv4-hf4:
201+
name: "🤙 Call container workflow with `opencv4-hf4`"
202+
needs: ['set-version', 'call-build-opencv4-torch2']
203+
uses: ./.github/workflows/container.yml
204+
secrets: inherit
205+
with:
206+
buildfilename: './container/opencv4-hf4.containerfile'
207+
version: ${{ needs.set-version.outputs.version }}
208+
209+
call-build-opencv4-hf5:
210+
name: "🤙 Call container workflow with `opencv4-hf5`"
211+
needs: ['set-version', 'call-build-opencv4-torch2']
212+
uses: ./.github/workflows/container.yml
213+
secrets: inherit
214+
with:
215+
buildfilename: './container/opencv4-hf5.containerfile'
216+
version: ${{ needs.set-version.outputs.version }}

.github/workflows/publish.yml

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,54 @@
1-
name: "📦 Publish (docs, PyPI)"
1+
name: "📦 Publish (PyPI + docs)"
22

3-
on:
4-
push:
5-
tags:
3+
on:
4+
push:
5+
tags:
66
- '[0-9]+.[0-9]+.[0-9]+'
7+
workflow_dispatch:
8+
inputs:
9+
version:
10+
description: 'Version to publish (e.g., 3.2.0)'
11+
required: true
712

813
jobs:
9-
packge-and-upload:
10-
name: "🤙 Call SDK publish workflow"
14+
check-pypi:
15+
name: "🔍 Check PyPI for existing package"
16+
runs-on: ubuntu-latest
17+
outputs:
18+
exists: ${{ steps.check.outputs.exists }}
19+
version: ${{ steps.check.outputs.version }}
20+
steps:
21+
- id: check
22+
run: |
23+
PACKAGE=$(echo "${{ github.repository }}" | cut -d/ -f2 | tr '-' '_')
24+
VERSION=${{ inputs.version || github.ref_name }}
25+
echo "version=$VERSION" >> $GITHUB_OUTPUT
26+
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://pypi.org/pypi/$PACKAGE/$VERSION/json")
27+
if [ "$STATUS" = "200" ]; then
28+
echo "Package $PACKAGE $VERSION already exists on PyPI, skipping upload"
29+
echo "exists=true" >> $GITHUB_OUTPUT
30+
else
31+
echo "Package $PACKAGE $VERSION not found on PyPI, proceeding with upload"
32+
echo "exists=false" >> $GITHUB_OUTPUT
33+
fi
34+
35+
publish-pypi:
36+
name: "📦 Build and upload to PyPI"
37+
needs: check-pypi
38+
if: needs.check-pypi.outputs.exists == 'false'
1139
uses: clamsproject/.github/.github/workflows/sdk-publish.yml@main
1240
secrets: inherit
1341

42+
publish-docs:
43+
name: "📖 Build and publish docs"
44+
needs: [check-pypi, publish-pypi]
45+
if: always() && needs.check-pypi.result == 'success' && needs.publish-pypi.result != 'failure'
46+
uses: clamsproject/clamsproject.github.io/.github/workflows/sdk-docs.yml@main
47+
with:
48+
source_repo: clamsproject/clams-python
49+
source_ref: ${{ needs.check-pypi.outputs.version }}
50+
project_name: clams-python
51+
build_command: 'python3 build-tools/docs.py --output-dir docs'
52+
docs_output_dir: 'docs'
53+
python_version: '3.11'
54+
secrets: inherit

build-tools/docs.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ def run_command(command, cwd=None, check=True, env=None):
1414
sys.exit(result.returncode)
1515
return result
1616

17-
def build_docs_local(source_dir: Path):
17+
def build_docs_local(source_dir: Path, output_dir: Path = None):
1818
"""
1919
Builds documentation for the provided source directory.
2020
Assumes it's running in an environment with necessary tools.
2121
"""
22+
if output_dir is None:
23+
output_dir = source_dir / "docs-test"
2224
print("--- Running in Local Build Mode ---")
2325

2426
# 1. Generate source code and install in editable mode.
@@ -49,7 +51,7 @@ def build_docs_local(source_dir: Path):
4951
# 3. Build the documentation using Sphinx.
5052
print("\n--- Step 3: Building Sphinx documentation ---")
5153
docs_source_dir = source_dir / "documentation"
52-
docs_build_dir = source_dir / "docs-test"
54+
docs_build_dir = output_dir
5355

5456
# Schema generation is now handled in conf.py
5557
# schema_src = source_dir / "clams" / "appmetadata.jsonschema"
@@ -74,9 +76,12 @@ def main():
7476
parser = argparse.ArgumentParser(
7577
description="Build documentation for the clams-python project."
7678
)
79+
parser.add_argument(
80+
'--output-dir', type=Path, default=None,
81+
help='Output directory for built docs (default: docs-test)')
7782
args = parser.parse_args()
78-
79-
build_docs_local(Path.cwd())
83+
84+
build_docs_local(Path.cwd(), output_dir=args.output_dir)
8085

8186
if __name__ == "__main__":
8287
main()

0 commit comments

Comments
 (0)