aboutsummaryrefslogtreecommitdiffstats
path: root/.github/workflows/lint-test-build-push.yaml
diff options
context:
space:
mode:
Diffstat (limited to '.github/workflows/lint-test-build-push.yaml')
-rw-r--r--.github/workflows/lint-test-build-push.yaml206
1 files changed, 206 insertions, 0 deletions
diff --git a/.github/workflows/lint-test-build-push.yaml b/.github/workflows/lint-test-build-push.yaml
new file mode 100644
index 0000000..a2ebbb5
--- /dev/null
+++ b/.github/workflows/lint-test-build-push.yaml
@@ -0,0 +1,206 @@
+name: Lint, Test, Build, Push
+
+on:
+ push:
+ branches:
+ - sebastiaan/backend/cache-docker-images
+
+
+jobs:
+ lint-test:
+ runs-on: ubuntu-latest
+ env:
+ # Determine whether or not we should build the
+ # final production image and push it to GHCR.
+ production_build: ${{ github.event_name != 'pull_request' &&
+ github.ref == 'refs/heads/sebastiaan/backend/cache-docker-images' }}
+
+ steps:
+ # Create a short SHA-tag to tag built images
+ - name: Create SHA Container Tag
+ id: sha_tag
+ run: |
+ tag=$(cut -c 1-7 <<< $GITHUB_SHA)
+ echo "::set-output name=tag::$tag"
+ - name: Checkout code
+ uses: actions/checkout@v2
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v1
+
+ - name: Login to Github Container Registry
+ uses: docker/login-action@v1
+ with:
+ registry: ghcr.io
+ username: ${{ github.repository_owner }}
+ password: ${{ secrets.GHCR_TOKEN }}
+
+ # Set up a caching directory for image layers. According to the docker
+ # documentation, it's recommended to use a SHA-based key to get the
+ # greatest change of finding the most relevant cached layer. We fall
+ # down to more generic containers by then matching by GitHub branch,
+ # to use cache generated earlier in the same branch, and finally to
+ # the latest cache in general. The `v0` is purely a cache version
+ # indicator that can be incremented manually if we want to invalidate
+ # old caches completely.
+ - name: Cache Image Layers
+ uses: actions/cache@v2
+ with:
+ path: /tmp/.buildx-cache
+ key: ${{ runner.os }}-v0-buildx-${{ github.ref }}-${{ github.sha }}
+ restore-keys: |
+ ${{ runner.os }}-v0-buildx-${{ github.ref }}-
+ ${{ runner.os }}-v0-buildx-
+
+ # Build the image we need for testing/linting the current codebase,
+ # without pushing the image to the GHCR. Instead, we load it into
+ # the runner's docker environment so we can run it later. The
+ # target of this build is the `venv` stage of the Dockerfile, as we
+ # don't want to include the final production entry point stage.
+ #
+ # This build caches to our GitHub Actions cache and uses that cache
+ # during the build process as well. If no GitHub Actions cache was
+ # available, it will use the latest intermediate images pushed to
+ # the GHCR as a cache source.
+ - name: Build image for linting and testing
+ uses: docker/build-push-action@v2
+ with:
+ context: .
+ file: ./docker/Dockerfile
+ push: false
+ load: true
+ target: venv
+ cache-from: |
+ type=local,src=/tmp/.buildx-cache
+ ghcr.io/python-discord/snekbox-base:latest
+ ghcr.io/python-discord/snekbox-venv:latest
+ cache-to: type=local,dest=/tmp/.buildx-cache,mode=max
+ tags: ghcr.io/python-discord/snekbox-venv:${{ steps.sha_tag.outputs.tag }}
+
+ - name: Start Container
+ run: "docker run \
+ --tty \
+ --detach \
+ --name snekbox_test \
+ --privileged \
+ --hostname pdsnk-dev \
+ -e PYTHONDONTWRITEBYTECODE=1 \
+ -e PIPENV_PIPFILE='/snekbox/Pipfile\' \
+ -e ENV=\"${PWD}/scripts/.profile\" \
+ --volume \"${PWD}\":\"${PWD}\" \
+ --workdir \"${PWD}\" \
+ --entrypoint /bin/bash \
+ ghcr.io/python-discord/snekbox-venv:${{ steps.sha_tag.outputs.tag }}"
+
+ - name: Install dependencies
+ run: "docker exec snekbox_test /bin/bash -c \
+ 'pipenv install --system --deploy --dev'"
+
+ # This runs `flake8` in the container and asks `flake8` to output
+ # linting errors in the format of the command for registering workflow
+ # error messages/annotations. This means that Github Actions will pick
+ # up on this output to generate nice annotations to indicate what went
+ # wrong where.
+ - name: Run linter
+ run: "docker exec snekbox_test /bin/bash -c 'flake8 \
+ --format \"::error file=%(path)s,line=%(row)d,col=%(col)d::\
+ [flake8] %(code)s: %(text)s\"'"
+
+ # Memory limit tests would fail if this isn't disabled.
+ - name: Disable swap memory
+ run: sudo swapoff -a
+
+ # Run unittests and generate coverage report in the container
+ - name: Run unit tests and generate coverage report
+ id: run_tests
+ run: |
+ echo '::set-output name=started::true'
+ cmd='coverage run -m unittest; coverage report -m'
+ docker exec snekbox_test /bin/bash -c "${cmd}"
+
+ # Set-up a Python version to process the coverage reports
+ # Note: This step runs even if the test step failed to make
+ # sure we process the coverage reports.
+ - name: Setup python
+ if: always() && steps.run_tests.outputs.started == 'true'
+ id: python
+ uses: actions/setup-python@v2
+ with:
+ python-version: '3.9'
+
+ # We'll only ever need a single dependency in this python
+ # environment and we'll only use it in the CI, so let's
+ # install it directly here and run it.
+ #
+ # This step will publish the coverage results to coveralls.io
+ # print a job link in the output. It will also register a
+ # step in the check suite visible in the PR with a link to
+ # the job.
+ - name: Publish coverage report to coveralls.io
+ if: always() && steps.run_tests.outputs.started == 'true'
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ pip install coveralls~=2.1
+ coveralls
+
+ # Final build stage. This is run in the same job with conditions
+ # to prevent us from having to reload the caching directory. We
+ # already built a huge chunk of the image before this point in
+ # the run, so it does not make sense to drop down to a completely
+ # fresh build environment in a new worker/runner.
+
+ # Build the final production image and push it to GHCR, tagging it
+ # both with the short commit SHA and 'latest'. This step should use
+ # the cache that was just generated when we built the test container.
+ - name: Build final image
+ if: env.production_build == 'true'
+ uses: docker/build-push-action@v2
+ with:
+ context: .
+ file: ./docker/Dockerfile
+ push: true
+ cache-from: |
+ type=local,src=/tmp/.buildx-cache
+ ghcr.io/python-discord/snekbox-base:latest
+ ghcr.io/python-discord/snekbox-venv:latest
+ ghcr.io/python-discord/snekbox:latest
+ cache-to: type=local,dest=/tmp/.buildx-cache
+ tags: |
+ ghcr.io/python-discord/snekbox:latest
+ ghcr.io/python-discord/snekbox:${{ steps.sha_tag.outputs.tag }}
+
+ # Push the base image to GHCR, *with* an inline cache manifest to
+ # ensure we can use this image as a cache source if our GitHub Actions
+ # "local" cache failed to be restored. GHCR does not support pushing a
+ # separate cache manifest, meaning we have to use an "inline" manifest.
+ - name: Push base image
+ if: env.production_build == 'true'
+ uses: docker/build-push-action@v2
+ with:
+ context: .
+ file: ./docker/Dockerfile
+ target: base
+ push: true
+ cache-from: |
+ type=local,src=/tmp/.buildx-cache
+ ghcr.io/python-discord/snekbox-base:latest
+ cache-to: type=inline
+ tags: ghcr.io/python-discord/snekbox-base:latest
+
+ # Push the venv image to GHCR *with* an inline cache manifest. See
+ # the comment attached to the previous step for more information.
+ - name: Push venv image
+ if: env.production_build == 'true'
+ uses: docker/build-push-action@v2
+ with:
+ context: .
+ file: ./docker/Dockerfile
+ target: venv
+ push: true
+ cache-from: |
+ type=local,src=/tmp/.buildx-cache
+ ghcr.io/python-discord/snekbox-base:latest
+ ghcr.io/python-discord/snekbox-venv:latest
+ cache-to: type=inline
+ tags: ghcr.io/python-discord/snekbox-venv:latest