diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..1e99947 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,128 @@ +# Continuous integration testing for ChRIS Plugin. +# https://github.com/FNNDSC/python-chrisapp-template/wiki/Continuous-Integration +# +# - on push and PR: run pytest +# - on push to main: build and push container images as ":latest" +# - on push to semver tag: build and push container image with tag and +# upload plugin description to https://chrisstore.co + +name: build + +on: + push: + branches: [ main ] + tags: + - "v?[0-9]+.[0-9]+.[0-9]+*" + pull_request: + branches: [ main ] + +jobs: + build: + name: Build + if: github.event_name == 'push' || github.event_name == 'release' + runs-on: ubuntu-22.04 + + steps: + - name: Decide image tags + id: info + shell: python + run: | + import os + import itertools + + def join_tag(t): + registry, repo, tag = t + return f'{registry}/{repo}:{tag}'.lower() + + registries = ['docker.io', 'ghcr.io'] + repos = ['${{ github.repository }}'] + if '${{ github.ref_type }}' == 'branch': + tags = ['latest'] + elif '${{ github.ref_type }}' == 'tag': + tag = '${{ github.ref_name }}' + version = tag[1:] if tag.startswith('v') else tag + tags = ['latest', version] + else: + tags = [] + + if '${{ github.ref_type }}' == 'tag': + local_tag = join_tag(('ghcr.io', '${{ github.repository }}', version)) + else: + local_tag = join_tag(('localhost', '${{ github.repository }}', 'latest')) + + product = itertools.product(registries, repos, tags) + tags_csv = ','.join(map(join_tag, product)) + outputs = { + 'tags_csv' : tags_csv, + 'push' : 'true' if tags_csv else 'false', + 'local_tag': local_tag + } + with open(os.environ['GITHUB_OUTPUT'], 'a') as out: + for k, v in outputs.items(): + out.write(f'{k}={v}\n') + + - uses: actions/checkout@v3 + # QEMU is used for non-x86_64 builds + - uses: docker/setup-qemu-action@v3 + # buildx adds additional features to docker build + - uses: docker/setup-buildx-action@v3 + with: + driver-opts: network=host + + # Here, we want to do the docker build twice: + # The first build pushes to our local registry for testing. + # The second build pushes to Docker Hub and ghcr.io + - name: Build (local only) + uses: docker/build-push-action@v3 + id: docker_build + with: + context: . + file: ./Dockerfile + tags: ${{ steps.info.outputs.local_tag }} + load: true + cache-from: type=gha + - name: Login to DockerHub + if: (github.event_name == 'push' || github.event_name == 'release') && contains(steps.info.outputs.tags_csv, 'docker.io') + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + - name: Login to GitHub Container Registry + if: (github.event_name == 'push' || github.event_name == 'release') && contains(steps.info.outputs.tags_csv, 'ghcr.io') + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build and push + uses: docker/build-push-action@v3 + if: (github.event_name == 'push' || github.event_name == 'release') + with: + context: . + file: ./Dockerfile + tags: ${{ steps.info.outputs.tags_csv }} + # linux/ppc64le not working, see https://github.com/ANTsX/ANTs/issues/1644 + platforms: linux/amd64,linux/arm64 + push: ${{ steps.info.outputs.push }} + cache-to: type=gha,mode=max + + - name: Upload ChRIS Plugin + id: upload + if: github.ref_type == 'tag' + uses: FNNDSC/upload-chris-plugin@v1 + with: + dock_image: ${{ steps.info.outputs.local_tag }} + username: ${{ secrets.CHRISPROJECT_USERNAME }} + password: ${{ secrets.CHRISPROJECT_PASSWORD }} + chris_url: https://cube.chrisproject.org/api/v1/ + compute_names: host,galena + + - name: Update DockerHub description + if: steps.upload.outcome == 'success' + uses: peter-evans/dockerhub-description@v3 + continue-on-error: true # it is not crucial that this works + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + short-description: ${{ steps.upload.outputs.title }} + readme-filepath: ./README.md \ No newline at end of file