From 9bd4a925388cd232299360edb9e6bfba9fadaf0f Mon Sep 17 00:00:00 2001 From: jselig-rigetti <97701976+jselig-rigetti@users.noreply.github.com> Date: Mon, 28 Aug 2023 13:27:45 -0600 Subject: [PATCH] feat: release docker images using github ci, not gitlab (#1636) * feat: release using github ci * chore: base on pyquil version, not repository tag * fix: use correct output setup and fully tested * fix: rc vs latest branch pushing from env vars not tag formatters * chore: add testing dockerfile --- .github/workflows/release.yml | 70 ++++++++++++++++++++++++++++++++++- .github/workflows/test.yml | 28 ++++++++++++++ .gitlab-ci.yml | 59 ----------------------------- Dockerfile | 2 +- Dockerfile.test | 33 +++++++++++++++++ pyproject.toml | 1 - 6 files changed, 130 insertions(+), 63 deletions(-) delete mode 100644 .gitlab-ci.yml create mode 100644 Dockerfile.test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5f5fb67ef..dc624da3e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,6 +6,10 @@ on: workflow_dispatch: description: "Manually publish release" +env: + # Only used ephemerally for validating image + DOCKER_TEST_TAG: "${{ env.DOCKER_IMAGE_NAME }}:test" + jobs: build-publish: name: Build and Publish @@ -13,11 +17,73 @@ jobs: steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v3 + - uses: snok/install-poetry@v1 + with: + virtualenvs-in-project: true - name: "Build" run: | - . scripts/ci_install_deps poetry build --no-interaction - - name: "Publish" + - id: publish + name: "Publish" run: | poetry config pypi-token.pypi ${{ secrets.PYPI_API_TOKEN }} poetry publish + export PYQUIL_TAG_VERSION=$(poetry version --short) + export PYQUIL_TAG_LATEST=$([[ "$PYQUIL_TAG_VERSION" =~ ^[0-9]+[.][0-9]+[.][0-9]+$ ]] && echo latest || echo) + export PYQUIL_TAG_RC=$([[ "$PYQUIL_TAG_VERSION" =~ ^[0-9]+[.][0-9]+[.][0-9]+-rc[.][0-9]+$ ]] && echo rc || echo) + echo "PYQUIL_TAG_VERSION=$PYQUIL_TAG_VERSION" >> "$GITHUB_OUTPUT" + echo "PYQUIL_TAG_LATEST=$PYQUIL_TAG_LATEST" >> "$GITHUB_OUTPUT" + echo "PYQUIL_TAG_RC=$PYQUIL_TAG_RC" >> "$GITHUB_OUTPUT" + outputs: + PYQUIL_TAG_VERSION: ${{ steps.publish.outputs.PYQUIL_TAG_VERSION }} + PYQUIL_TAG_LATEST: ${{ steps.publish.outputs.PYQUIL_TAG_LATEST }} + PYQUIL_TAG_RC: ${{ steps.publish.outputs.PYQUIL_TAG_RC }} + docker-publish: + name: Docker Publish + runs-on: ubuntu-latest + needs: build-publish + env: + PYQUIL_TAG_VERSION: ${{ needs.build-publish.outputs.PYQUIL_TAG_VERSION }} + PYQUIL_TAG_LATEST: ${{ needs.build-publish.outputs.PYQUIL_TAG_LATEST }} + PYQUIL_TAG_RC: ${{ needs.build-publish.outputs.PYQUIL_TAG_RC }} + steps: + # Determine the tags to publish based on the release tag + - name: Docker Metadata + id: meta + uses: docker/metadata-action@v4 + with: + images: | + ${{ env.DOCKER_IMAGE_NAME }} + tags: | + type=raw,value=${{ env.PYQUIL_TAG_VERSION }} + type=raw,value=${{ env.PYQUIL_TAG_LATEST }},enable=${{ env.PYQUIL_TAG_LATEST != '' }} + type=raw,value=${{ env.PYQUIL_TAG_RC }},enable=${{ env.PYQUIL_TAG_RC != '' }} + # Checkout is needed to use the path context: . + - name: Checkout + uses: actions/checkout@v3 + - name: Build and Test + uses: docker/build-push-action@v4 + with: + context: . + load: true + tags: ${{ env.DOCKER_TEST_TAG }} + build-args: | + pyquil_version=${{ env.PYQUIL_TAG_VERSION }} + - name: Test Image + run: | + docker run --rm ${{ env.DOCKER_TEST_TAG }} python -c "from pyquil import get_qc" + # Build and publish the image + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + - name: Build and Push + uses: docker/build-push-action@v4 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + pyquil_version=${{ env.PYQUIL_TAG_VERSION }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f323ff73e..d6ca37734 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -163,6 +163,34 @@ jobs: thresholdNew: 0.9 token: ${{ secrets.PAT }} + check-docker-image: + name: Check types + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: '3.8' + - uses: actions/cache@v2 + with: + path: .venv + key: poetry-${{ hashFiles('poetry.lock') }} + - name: Check types + run: | + sudo apt update + pip wheel . -w wheels + - name: Build and Test + uses: docker/build-push-action@v4 + with: + file: Dockerfile.test + context: . + load: true + tags: test + - name: Test Image + run: | + docker run --rm test python -c "from pyquil import get_qc" + test-e2e: name: Test e2e QVM runs-on: ubuntu-latest diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 3e66f47db..000000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,59 +0,0 @@ -default: - image: python:3.8 - tags: - - ec2-docker - -stages: - - docker - -cache: - key: "${CI_COMMIT_REF_SLUG}" - paths: - - .cache/pip - - .venv - -#################################################################################################### -# RELEASE-ONLY JOBS -#################################################################################################### - -.docker-publish: - image: docker:git - stage: docker - tags: - - dockerd - script: - - export VERSION_TAG=$(cat version_tag) - - echo "Publishing images:" - - echo " ${IMAGE}:${VERSION_TAG}" - - echo " ${IMAGE}:${EXTRA_TAG}" - - docker -v - - echo ${DOCKERHUB_PASSWORD} | docker login -u ${DOCKERHUB_USERNAME} --password-stdin - - docker build --build-arg pyquil_version=${VERSION_TAG} -t ${IMAGE}:${VERSION_TAG} -t ${IMAGE}:${EXTRA_TAG} . - - docker push ${IMAGE}:${VERSION_TAG} && docker push ${IMAGE}:${EXTRA_TAG} - after_script: - - docker rmi $(docker images --format '{{.Repository}}:{{.Tag}}' | grep ${IMAGE}) - - docker run --rm ${IMAGE}:${VERSION_TAG} python -c "from pyquil import get_qc; qvm = get_qc('9q-qvm')" # simple image verification - - docker rmi $(docker images --format '{{.Repository}}:{{.Tag}}' | grep ${IMAGE}) - # sometimes pyquil isn't ready on PyPI right away, so add a retry if docker build fails - retry: - max: 2 - when: script_failure - -# TODO: Migrate Docker Publish tasks to GitHub -# See https://github.com/rigetti/pyquil/issues/1548 -Docker Publish (RC): - extends: .docker-publish - rules: - - when: never - - if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+-rc\.\d+$/ - variables: - EXTRA_TAG: rc - -Docker Publish (Final): - services: [] - extends: .docker-publish - rules: - - when: never - - if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/ - variables: - EXTRA_TAG: latest diff --git a/Dockerfile b/Dockerfile index 2f49e0de3..a8ba41fde 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # use multi-stage builds to independently pull dependency versions ARG quilc_version=1.20.0 ARG qvm_version=1.17.1 -ARG python_version=3.7 +ARG python_version=3.8 # use multi-stage builds to independently pull dependency versions FROM rigetti/quilc:$quilc_version as quilc diff --git a/Dockerfile.test b/Dockerfile.test new file mode 100644 index 000000000..942526384 --- /dev/null +++ b/Dockerfile.test @@ -0,0 +1,33 @@ +# use multi-stage builds to independently pull dependency versions +ARG quilc_version=1.20.0 +ARG qvm_version=1.17.1 +ARG python_version=3.8 + +# use multi-stage builds to independently pull dependency versions +FROM rigetti/quilc:$quilc_version as quilc +FROM rigetti/qvm:$qvm_version as qvm +FROM python:$python_version-buster + +# copy over the pre-built quilc binary from the first build stage +COPY --from=quilc /src/quilc/quilc /src/quilc/quilc + +# copy over the pre-built qvm binary from the second build stage +COPY --from=qvm /src/qvm/qvm /src/qvm/qvm + +# install the missing apt packages that aren't copied over +RUN apt-get update && apt-get -yq dist-upgrade && \ + apt-get install --no-install-recommends -yq \ + git libblas-dev libffi-dev liblapack-dev libzmq3-dev && \ + rm -rf /var/lib/apt/lists/* + +# install ipython +RUN pip install --no-cache-dir ipython + +# install pyquil from local wheel +COPY ./wheels /src/wheels +RUN pip install /src/wheels/pyquil-*.whl + +# use an entrypoint script to add startup commands (qvm & quilc server spinup) +COPY ./entrypoint.sh /src/pyquil/entrypoint.sh +ENTRYPOINT ["/src/pyquil/entrypoint.sh"] +CMD ["ipython"] diff --git a/pyproject.toml b/pyproject.toml index 63a7040d0..027ec3fa9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,6 @@ license = "Apache-2.0" classifiers = [ "Development Status :: 5 - Production/Stable", "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Operating System :: OS Independent",