From 0bf0b7c9d24585e8774aaf087634980acd7ad369 Mon Sep 17 00:00:00 2001 From: Jennings Zhang Date: Mon, 16 Oct 2023 17:17:01 -0400 Subject: [PATCH] Update ci.yml --- .github/workflows/ci.yml | 196 ++++++++++++++++----------------------- release.sh | 61 ------------ 2 files changed, 81 insertions(+), 176 deletions(-) delete mode 100755 release.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4f13df8..aa61885 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,151 +14,117 @@ name: ci on: push: # we have to guess what the name of the default branch is - branches: [ master, main, trunk ] - tags: [ '**' ] + branches: [ master ] + tags: [ "[0-9]+.[0-9]+.[0-9]+*" ] pull_request: - branches: [ master, main, trunk ] - release: - types: [ created ] + branches: [ master ] jobs: - test: - runs-on: ubuntu-20.04 + build: + name: Build + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 - - name: build - run: docker build -t "${GITHUB_REPOSITORY,,}" . - - name: nose tests - run: docker run "${GITHUB_REPOSITORY,,}" nosetests - - publish: - if: github.event_name == 'push' || github.event_name == 'release' - runs-on: ubuntu-20.04 - - # we want to both push the build to DockerHub, but also - # keep a local copy so that we can run - # - # docker run fnndsc/pl-app app --json > App.json - # - # buildx currently does not support multiple output locations, - # neither can multi-architectural builds be loaded into docker. - # Here we use a local registry to cache the build. - services: - registry: - image: registry:2 - ports: - - 5000:5000 - - steps: - - name: Get git tag - id: git_info - if: startsWith(github.ref, 'refs/tags/') - run: echo "::set-output name=tag::${GITHUB_REF##*/}" - - name: Decide image tag name - id: determine - env: - git_tag: ${{ steps.git_info.outputs.tag }} + - name: Decide image tags + id: info + shell: python run: | - repo="${GITHUB_REPOSITORY,,}" # to lower case - # if build triggered by tag, use tag name - tag="${git_tag:-latest}" - dock_image=$repo:$tag - echo $dock_image - echo "::set-output name=dock_image::$dock_image" - echo "::set-output name=repo::$repo" + import os + import itertools + + registries = ['docker.io', 'ghcr.io'] + repos = ['${{ github.repository }}'] + if '${{ github.ref_type }}' == 'branch': + version = 'unknown' + 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 = [] - - uses: actions/checkout@v2 + def join_tag(t): + registry, repo, tag = t + return f'{registry}/{repo}:{tag}'.lower() - # QEMU is for emulating non-x86_64 platforms - - uses: docker/setup-qemu-action@v1 - # buildx is the next-generation docker image builder - - uses: docker/setup-buildx-action@v1 + 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': join_tag(('localhost', '${{ github.repository }}', 'latest')), + 'one_tag': join_tag(('ghcr.io', repos[0], version)) + } + 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 - # save some time during rebuilds - - name: Cache Docker layers - uses: actions/cache@v2 + + # 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: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx- + context: . + file: ./Dockerfile + tags: ${{ steps.info.outputs.local_tag }} + load: true + cache-from: type=gha - name: Login to DockerHub - id: dockerhub_login - uses: docker/login-action@v1 + 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 - uses: docker/login-action@v1 + 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@v2 - id: docker_build + uses: docker/build-push-action@v3 + if: (github.event_name == 'push' || github.event_name == 'release') with: context: . file: ./Dockerfile - tags: | - ${{ steps.determine.outputs.dock_image }} - localhost:5000/${{ steps.determine.outputs.dock_image }} - ghcr.io/${{ steps.determine.outputs.dock_image }} - platforms: linux/amd64 - push: true - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache + tags: ${{ steps.info.outputs.tags_csv }} + platforms: linux/amd64,linux/arm64,linux/ppc64le + push: ${{ steps.info.outputs.push }} + cache-to: type=gha,mode=max - - name: Get plugin meta - id: pluginmeta + - name: Create plugin description run: | - repo=${{ steps.determine.outputs.repo }} - dock_image=${{ steps.determine.outputs.dock_image }} - docker pull localhost:5000/$dock_image - docker tag localhost:5000/$dock_image $dock_image - script=$(docker inspect --format '{{ (index .Config.Cmd 0) }}' $dock_image) - json="$(docker run --rm $dock_image $script --json)" - jq <<< "$json" # pretty print in log - - echo "::set-output name=json::$json" - echo "::set-output name=title::$(jq -r '.title' <<< "$json")" + docker run --rm ${{ steps.info.outputs.local_tag }} dircopy --json \ + | jq '. + {"name": "pl-dircopy", "public_repo": "${{ github.server_url }}/${{ github.repository }}", "dock_image": "${{ steps.info.outputs.one_tag }}"}' > ./Dircopy.json + - name: Upload ChRIS Plugin + id: upload + if: github.ref_type == 'tag' + uses: FNNDSC/upload-chris-plugin@v1 + with: + description_file: ./Dircopy.json + username: ${{ secrets.CHRISPROJECT_USERNAME }} + password: ${{ secrets.CHRISPROJECT_PASSWORD }} + chris_url: https://cube.chrisproject.org/api/v1/ + compute_names: host - name: Update DockerHub description - uses: peter-evans/dockerhub-description@v2 + 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.pluginmeta.outputs.title }} + short-description: ${{ steps.upload.outputs.title }} readme-filepath: ./README.rst - repository: ${{ steps.determine.outputs.repo }} - - - name: Upload to ChRIS Store - if: "!endsWith(steps.determine.outputs.dock_image, ':latest')" - run: | - repo=${{ steps.determine.outputs.repo }} - dock_image=${{ steps.determine.outputs.dock_image }} - descriptor_file=$(mktemp --suffix .json) - cat > $descriptor_file <<< '${{ steps.pluginmeta.outputs.json }}' - res=$( - curl -s -u "${{ secrets.CHRIS_STORE_USER }}" "https://chrisstore.co/api/v1/plugins/" \ - -F "name=$(sed 's/^.*\///' <<< $repo)" \ - -F "dock_image=$dock_image" \ - -F "descriptor_file=@$descriptor_file" \ - -F "public_repo=https://github.com/${{ github.repository }}" - ) - success=$? - if [ "$success" = "0" ]; then - href="$(jq -r '.collection.items[0].href' <<< "$res")" - echo $href - echo "::set-output name=pluginurl::$href" - else - echo "::error ::Failed upload to ChRIS Store" - echo "$res" - exit $success - fi - diff --git a/release.sh b/release.sh deleted file mode 100755 index 3131b9a..0000000 --- a/release.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash - -G_SYNOPSIS=" - - NAME - - release.sh - - SYNOPSIS - - release.sh [--pypi] - - ARGS - - - A version string. For best practices make this version the same as - the VERSION class variable defined in your main plugin app class. - - --pypi - Optional flag to also upload the new version to PyPI. - - DESCRIPTION - - release.sh is a simple helper script to tag and upload a new version of the plugin - app to Github. If --pypi is passed then the new version is also uploaded to PyPI - (Python Package Index). - - -" - -if [[ "$#" -eq 0 ]] || [[ "$#" -gt 2 ]]; then - echo "$G_SYNOPSIS" - exit 1 -fi -VER=$1 -if [[ "$#" -eq 2 ]]; then - if [[ "$1" != '--pypi' ]] && [[ "$2" != '--pypi' ]]; then - echo "$G_SYNOPSIS" - exit 1 - fi - if [[ "$1" == '--pypi' ]]; then - VER=$2 - fi -fi -if [[ $VER =~ ^[0-9.]+$ ]]; then - echo Pushing $VER to Github ... - git add -A - git commit -m "v${VER}" - git push origin master - git tag $VER - git push origin --tags -else - echo "Invalid version number format $VER." - exit 1 -fi -if [[ "$#" -eq 2 ]]; then - echo pushing $VER to PyPI ... - rstcheck README.rst - python3 setup.py sdist - twine upload dist/{{ cookiecutter.app_name }}-${VER}.tar.gz -fi