44# - on push and PR: run pytest
55# - on push to main: build and push container images as ":latest"
66# - on push to semver tag: build and push container image with tag and
7- # upload plugin description to https://chrisstore.co
7+ # upload plugin description to https://cube.chrisproject.org/api/v1/
88
99name : build
1010
1919jobs :
2020 test :
2121 name : Unit tests
22- if : false # delete this line to enable automatic testing
22+ if : False
2323 runs-on : ubuntu-22.04
2424 steps :
25- - uses : actions/checkout@v3
26- - uses : docker/setup-buildx-action@v2
27- - name : Cache Docker layers
28- uses : actions/cache@v2
29- with :
30- path : /tmp/.buildx-cache
31- key : ${{ runner.os }}-buildx-${{ github.sha }}
32- restore-keys : |
33- ${{ runner.os }}-buildx-
25+ - uses : actions/checkout@v4
26+ - uses : docker/setup-buildx-action@v3
3427 - name : Build
35- uses : docker/build-push-action@v3
28+ uses : docker/build-push-action@v5
3629 with :
3730 build-args : extras_require=dev
3831 context : .
3932 load : true
4033 push : false
4134 tags : " localhost/local/app:dev"
42- cache-from : type=local,src=/tmp/.buildx-cache
43- cache-to : type=local,dest=/tmp/.buildx-cache
35+ cache-from : type=gha
36+ cache-to : type=gha,mode=max
4437 - name : Run pytest
4538 run : |
4639 docker run -v "$GITHUB_WORKSPACE:/app:ro" -w /app localhost/local/app:dev \
@@ -52,105 +45,138 @@ jobs:
5245 # needs: [ test ] # uncomment to require passing tests
5346 runs-on : ubuntu-22.04
5447
55- # A local registry helps us reuse the built image between steps
56- services :
57- registry :
58- image : registry:2
59- ports :
60- - 5000:5000
61-
6248 steps :
63- - name : Get git tag
64- id : git_info
65- if : startsWith(github.ref, 'refs/tags/')
66- run : echo "::set-output name=tag::${GITHUB_REF##*/}"
67- - name : Get project info
68- id : determine
69- env :
70- git_tag : ${{ steps.git_info.outputs.tag }}
49+ - name : Decide image tags
50+ id : info
51+ shell : python
7152 run : |
72- repo="${GITHUB_REPOSITORY,,}" # to lower case
73- # if build triggered by tag, use tag name
74- tag="${git_tag:-latest}"
53+ import os
54+ import itertools
7555
76- # if tag is a version number prefixed by 'v', remove the 'v'
77- if [[ "$tag" =~ ^v[0-9].* ]]; then
78- tag="${tag:1}"
79- fi
56+ def join_tag(t):
57+ registry, repo, tag = t
58+ return f'{registry}/{repo}:{tag}'.lower()
59+
60+ registries = ['docker.io', 'ghcr.io']
61+ repos = ['${{ github.repository }}']
62+ if '${{ github.ref_type }}' == 'branch':
63+ tags = ['latest']
64+ elif '${{ github.ref_type }}' == 'tag':
65+ tag = '${{ github.ref_name }}'
66+ version = tag[1:] if tag.startswith('v') else tag
67+ tags = ['latest', version]
68+ else:
69+ tags = []
70+
71+ if '${{ github.ref_type }}' == 'tag':
72+ local_tag = join_tag(('ghcr.io', '${{ github.repository }}', version))
73+ else:
74+ local_tag = join_tag(('localhost', '${{ github.repository }}', 'latest'))
8075
81- dock_image=$repo:$tag
82- echo $dock_image
83- echo "::set-output name=dock_image::$dock_image"
84- echo "::set-output name=repo::$repo"
76+ product = itertools.product(registries, repos, tags)
77+ tags_csv = ','.join(map(join_tag, product))
78+ outputs = {
79+ 'tags_csv' : tags_csv,
80+ 'push' : 'true' if tags_csv else 'false',
81+ 'local_tag': local_tag
82+ }
83+ with open(os.environ['GITHUB_OUTPUT'], 'a') as out:
84+ for k, v in outputs.items():
85+ out.write(f'{k}={v}\n')
8586
86- - uses : actions/checkout@v3
87+ - uses : actions/checkout@v4
8788 # QEMU is used for non-x86_64 builds
88- - uses : docker/setup-qemu-action@v2
89+ - uses : docker/setup-qemu-action@v3
8990 # buildx adds additional features to docker build
90- - uses : docker/setup-buildx-action@v2
91+ - uses : docker/setup-buildx-action@v3
9192 with :
9293 driver-opts : network=host
93- # cache slightly improves rebuild time
94- - name : Cache Docker layers
95- uses : actions/cache@v2
94+
95+ # Here, we want to do the docker build twice:
96+ # The first build pushes to our local registry for testing.
97+ # The second build pushes to Docker Hub and ghcr.io
98+ - name : Build (local only)
99+ uses : docker/build-push-action@v3
100+ id : docker_build
96101 with :
97- path : /tmp/.buildx-cache
98- key : ${{ runner.os }}-buildx-${{ github.sha }}
99- restore-keys : |
100- ${{ runner.os }}-buildx-
102+ context : .
103+ file : ./Dockerfile
104+ tags : ${{ steps.info.outputs.local_tag }}
105+ load : true
106+ cache-from : type=gha
107+ # If you have a directory called examples/incoming/ and examples/outgoing/, then
108+ # run your ChRIS plugin with no parameters, and assert that it creates all the files
109+ # which are expected. File contents are not compared.
110+ - name : Run examples
111+ id : run_examples
112+ run : |
113+ if ! [ -d 'examples/incoming/' ] || ! [ -d 'examples/outgoing/' ]; then
114+ echo "No examples."
115+ exit 0
116+ fi
117+
118+ dock_image=${{ steps.info.outputs.local_tag }}
119+ output_dir=$(mktemp -d)
120+ cmd=$(docker image inspect -f '{{ (index .Config.Cmd 0) }}' $dock_image)
121+ docker run --rm -u "$(id -u):$(id -g)" \
122+ -v "$PWD/examples/incoming:/incoming:ro" \
123+ -v "$output_dir:/outgoing:rw" \
124+ $dock_image $cmd /incoming /outgoing
125+
126+ for expected_file in $(find examples/outgoing -type f); do
127+ fname="${expected_file##*/}"
128+ out_path="$output_dir/$fname"
129+ printf "Checking output %s exists..." "$out_path"
130+ if [ -f "$out_path" ]; then
131+ echo "ok"
132+ else
133+ echo "not found"
134+ exit 1
135+ fi
136+ done
101137
102138 - name : Login to DockerHub
103- id : dockerhub_login
104- uses : docker/login-action@v2
139+ if : (github.event_name == 'push' || github.event_name == 'release') && contains(steps.info.outputs.tags_csv, 'docker.io')
140+ uses : docker/login-action@v3
105141 with :
106142 username : ${{ secrets.DOCKERHUB_USERNAME }}
107143 password : ${{ secrets.DOCKERHUB_PASSWORD }}
108-
109144 - name : Login to GitHub Container Registry
110- uses : docker/login-action@v2
145+ if : (github.event_name == 'push' || github.event_name == 'release') && contains(steps.info.outputs.tags_csv, 'ghcr.io')
146+ uses : docker/login-action@v3
111147 with :
112148 registry : ghcr.io
113149 username : ${{ github.repository_owner }}
114150 password : ${{ secrets.GITHUB_TOKEN }}
115-
116151 - name : Build and push
117- uses : docker/build-push-action@v3
118- id : docker_build
152+ uses : docker/build-push-action@v5
153+ if : (github.event_name == 'push' || github.event_name == 'release')
119154 with :
120155 context : .
121156 file : ./Dockerfile
122- tags : |
123- localhost:5000/${{ steps.determine.outputs.dock_image }}
124- docker.io/${{ steps.determine.outputs.dock_image }}
125- ghcr.io/${{ steps.determine.outputs.dock_image }}
157+ tags : ${{ steps.info.outputs.tags_csv }}
126158 # if non-x86_84 architectures are supported, add them here
127159 platforms : linux/amd64 # ,linux/arm64,linux/ppc64le
128- push : true
129- cache-from : type=local,src=/tmp/.buildx-cache
130- cache-to : type=local,dest=/tmp/.buildx-cache
160+ push : ${{ steps.info.outputs.push }}
161+ cache-to : type=gha,mode=max
131162
132- - name : Get plugin meta
133- id : pluginmeta
134- run : |
135- repo=${{ steps.determine.outputs.repo }}
136- dock_image=${{ steps.determine.outputs.dock_image }}
137- docker run --rm localhost:5000/$dock_image chris_plugin_info > /tmp/description.json
138- jq < /tmp/description.json # pretty print in log
139- echo "::set-output name=title::$(jq -r '.title' < /tmp/description.json)"
163+ - name : Upload ChRIS Plugin
164+ id : upload
165+ if : github.ref_type == 'tag'
166+ uses : FNNDSC/upload-chris-plugin@v1
167+ with :
168+ dock_image : ${{ steps.info.outputs.local_tag }}
169+ username : ${{ secrets.CHRISPROJECT_USERNAME }}
170+ password : ${{ secrets.CHRISPROJECT_PASSWORD }}
171+ chris_url : https://cube.chrisproject.org/api/v1/
172+ compute_names : NERC
140173
141174 - name : Update DockerHub description
142- uses : peter-evans/dockerhub-description@v2
175+ if : steps.upload.outcome == 'success'
176+ uses : peter-evans/dockerhub-description@v3
143177 continue-on-error : true # it is not crucial that this works
144178 with :
145179 username : ${{ secrets.DOCKERHUB_USERNAME }}
146180 password : ${{ secrets.DOCKERHUB_PASSWORD }}
147- short-description : ${{ steps.pluginmeta.outputs.title }}
148- readme-filepath : ./README.md
149- repository : ${{ steps.determine.outputs.repo }}
150-
151- - name : Upload to ChRIS Store
152- if : steps.git_info.outcome != 'skipped'
153- uses : FNNDSC/chrisstore-action@master
154- with :
155- descriptor_file : /tmp/description.json
156- auth : ${{ secrets.CHRIS_STORE_USER }}
181+ short-description : ${{ steps.upload.outputs.title }}
182+ readme-filepath : ./README.md
0 commit comments