aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/lint-test-build-push.yaml207
-rw-r--r--Pipfile17
-rw-r--r--README.md16
-rw-r--r--azure-pipelines.yml20
-rw-r--r--ci/build.yml51
-rw-r--r--ci/lint-test.yml41
-rw-r--r--ci/push.yml39
-rw-r--r--ci/setup.yml23
-rw-r--r--docker-compose.yml2
-rw-r--r--docker/Dockerfile58
-rw-r--r--docker/base.Dockerfile34
-rw-r--r--docker/venv.Dockerfile20
-rwxr-xr-xscripts/check_dockerfiles.sh127
-rwxr-xr-xscripts/dev.sh9
14 files changed, 289 insertions, 375 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..641b4e6
--- /dev/null
+++ b/.github/workflows/lint-test-build-push.yaml
@@ -0,0 +1,207 @@
+name: Lint, Test, Build, Push
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+
+
+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
diff --git a/Pipfile b/Pipfile
index 8c55df6..a8886c6 100644
--- a/Pipfile
+++ b/Pipfile
@@ -61,26 +61,29 @@ snekbox = "gunicorn -c config/gunicorn.conf.py snekbox.api.app"
devsh = "sh scripts/dev.sh"
build = """
docker build \
- -t pythondiscord/snekbox:latest \
+ -t ghcr.io/python-discord/snekbox:latest \
-f docker/Dockerfile \
.
"""
buildbase = """
docker build \
- -t pythondiscord/snekbox-base:latest \
- -f docker/base.Dockerfile \
+ -t ghcr.io/python-discord/snekbox-base:latest \
+ -f docker/Dockerfile \
+ --target base \
.
"""
buildvenv = """
docker build \
- -t pythondiscord/snekbox-venv:latest \
- -f docker/venv.Dockerfile \
+ -t ghcr.io/python-discord/snekbox-venv:latest \
+ -f docker/Dockerfile \
+ --target venv \
.
"""
builddev = """
docker build \
- -t pythondiscord/snekbox-venv:dev \
- -f docker/venv.Dockerfile \
+ -t ghcr.io/python-discord/snekbox-venv:dev \
+ -f docker/Dockerfile \
+ --target venv \
--build-arg DEV=1 \
.
"""
diff --git a/README.md b/README.md
index dba2709..4ebe3b6 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[![Build Status][1]][2]
+[![Build Status][1]][2] [![Coverage Status][3]][4]
# snekbox
@@ -33,10 +33,10 @@ See [`snekapi.py`] and [`resources`] for API documentation.
## Running snekbox
-A Docker image is available on [Docker Hub]. A container can be started with the following command, which will also pull the image if it doesn't currently exist locally:
+A Docker image is available in the [GitHub Container Registry]. A container can be started with the following command, which will also pull the image if it doesn't currently exist locally:
```
-docker run --ipc=none --privileged -p 8060:8060 pythondiscord/snekbox
+docker run --ipc=none --privileged -p 8060:8060 ghcr.io/python-discord/snekbox
```
To run it in the background, use the `-d` option. See the documentation on [`docker run`] for more information.
@@ -47,7 +47,7 @@ The above command will make the API accessible on the host via `http://localhost
### Initial Setup
-A Python 3.8 interpreter and the [pipenv] package are required. Once those requirements are satisfied, install the project's dependencies:
+A Python 3.9 interpreter and the [pipenv] package are required. Once those requirements are satisfied, install the project's dependencies:
```
pipenv sync --dev
@@ -142,8 +142,10 @@ nsjpy "print('hello world!')"
The alias can be found in `./scripts/.profile`, which is automatically added when the shell is launched in the container.
-[1]: https://dev.azure.com/python-discord/Python%20Discord/_apis/build/status/Snekbox?branchName=master
-[2]: https://dev.azure.com/python-discord/Python%20Discord/_build/latest?definitionId=13&branchName=master
+[1]: https://github.com/python-discord/snekbox/workflows/Lint,%20Test,%20Build,%20Push/badge.svg?branch=master
+[2]: https://github.com/python-discord/snekbox/actions?query=workflow%3A%22Lint%2C+Test%2C+Build%2C+Push%22+branch%3Amaster
+[3]: https://coveralls.io/repos/github/python-discord/snekbox/badge.svg?branch=master
+[4]: https://coveralls.io/github/python-discord/snekbox?branch=master
[`snekbox.cfg`]: config/snekbox.cfg
[`snekapi.py`]: snekbox/api/snekapi.py
[`resources`]: snekbox/api/resources
@@ -151,5 +153,5 @@ The alias can be found in `./scripts/.profile`, which is automatically added whe
[nsjail]: https://github.com/google/nsjail
[falcon]: https://falconframework.org/
[gunicorn]: https://gunicorn.org/
-[docker hub]: https://hub.docker.com/r/pythondiscord/snekbox
+[GitHub Container Registry]: https://github.com/orgs/python-discord/packages/container/package/snekbox
[pipenv]: https://docs.pipenv.org/en/latest/
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
deleted file mode 100644
index 573e3cc..0000000
--- a/azure-pipelines.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-# https://aka.ms/yaml
-
-jobs:
- - job: build_lint_test_push
- displayName: 'Build, Lint, Test, & Push'
-
- pool:
- vmImage: 'ubuntu-18.04'
-
- variables:
- BASE_CHANGED: 'True'
- VENV_CHANGED: 'True'
- BASE_PULL: 'False'
- VENV_PULL: 'False'
-
- steps:
- - template: ci/build.yml
- - template: ci/setup.yml
- - template: ci/lint-test.yml
- - template: ci/push.yml
diff --git a/ci/build.yml b/ci/build.yml
deleted file mode 100644
index 7d51709..0000000
--- a/ci/build.yml
+++ /dev/null
@@ -1,51 +0,0 @@
-steps:
- - task: ShellScript@2
- displayName: 'Check If Images Need to Be Built'
- inputs:
- scriptPath: scripts/check_dockerfiles.sh
- disableAutoCwd: true
-
- # Without a login, the following Docker build steps wouldn't add image tags.
- - task: Docker@1
- displayName: 'Log into Docker Hub'
- inputs:
- command: login
- containerregistrytype: 'Container Registry'
- dockerRegistryEndpoint: 'DockerHub'
-
- # Building the venv depends on this base image. Build the base if it can't
- # pulled from Docker Hub, which will be the case if the base Dockerfile has
- # has had changes.
- - script: |
- docker build \
- -f docker/base.Dockerfile \
- -t pythondiscord/snekbox-base:latest \
- .
- displayName: 'Build Base Image'
- condition: >
- and(
- succeeded(),
- or(
- eq(variables.BASE_CHANGED, 'True'),
- and(
- eq(variables.VENV_CHANGED, 'True'),
- eq(variables.BASE_PULL, 'False')
- )
- )
- )
-
- # Build the venv image if it's had changes or it can't be pulled.
- - script: |
- docker build \
- -f docker/venv.Dockerfile \
- -t pythondiscord/snekbox-venv:latest \
- .
- displayName: 'Build Virtual Environment Image'
- condition: >
- and(
- succeeded(),
- or(
- eq(variables.VENV_CHANGED, 'True'),
- eq(variables.VENV_PULL, 'False')
- )
- )
diff --git a/ci/lint-test.yml b/ci/lint-test.yml
deleted file mode 100644
index 2d70f6e..0000000
--- a/ci/lint-test.yml
+++ /dev/null
@@ -1,41 +0,0 @@
-steps:
- - script: |
- docker exec snekbox_test /bin/bash -c \
- 'flake8; flake8 --format junit-xml --output-file test-lint.xml'
- displayName: 'Run Linter'
-
- - task: PublishTestResults@2
- displayName: 'Publish Lint Results'
- condition: succeededOrFailed()
- inputs:
- testResultsFiles: '**/test-lint.xml'
- testRunTitle: 'Lint Results'
-
- # Memory limit tests would fail if this isn't disabled.
- - script: sudo swapoff -a
- displayName: 'Disable Swap Memory'
-
- - script: |
- docker exec snekbox_test /bin/bash -c \
- 'coverage run -m xmlrunner'
- displayName: 'Run Unit Tests'
-
- - task: PublishTestResults@2
- displayName: 'Publish Test Results'
- condition: succeededOrFailed()
- inputs:
- testResultsFiles: '**/TEST-*.xml'
- testRunTitle: 'Test Results'
-
- # Run report too because the XML report doesn't output to stdout.
- - script: |
- docker exec snekbox_test /bin/bash -c \
- 'coverage report && coverage xml'
- displayName: 'Generate Coverage Report'
-
- - task: PublishCodeCoverageResults@1
- displayName: 'Publish Coverage Results'
- condition: succeededOrFailed()
- inputs:
- codeCoverageTool: Cobertura
- summaryFileLocation: '**/coverage.xml'
diff --git a/ci/push.yml b/ci/push.yml
deleted file mode 100644
index 9449df0..0000000
--- a/ci/push.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-steps:
- # Always build this image unless it's for a pull request.
- - script: |
- docker build \
- -f docker/Dockerfile \
- -t pythondiscord/snekbox:latest \
- .
- displayName: 'Build Final Image'
- condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
-
- # Push images only after they've all successfully been built.
- - script: docker push pythondiscord/snekbox-base:latest
- displayName: 'Push Base Image'
- condition: >
- and(
- succeeded(),
- ne(variables['Build.Reason'], 'PullRequest'),
- ne(variables.BASE_PULL, 'True'),
- or(
- eq(variables.BASE_CHANGED, 'True'),
- eq(variables.VENV_CHANGED, 'True')
- )
- )
-
- - script: docker push pythondiscord/snekbox-venv:latest
- displayName: 'Push Virtual Environment Image'
- condition: >
- and(
- succeeded(),
- ne(variables['Build.Reason'], 'PullRequest'),
- or(
- eq(variables.BASE_CHANGED, 'True'),
- eq(variables.VENV_CHANGED, 'True')
- )
- )
-
- - script: docker push pythondiscord/snekbox:latest
- displayName: 'Push Final Image'
- condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
diff --git a/ci/setup.yml b/ci/setup.yml
deleted file mode 100644
index 1c66aa7..0000000
--- a/ci/setup.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-steps:
- # The linter and all tests run inside this container.
- # The venv image will be pulled if it doesn't exist locally.
- - script: |
- 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 \
- pythondiscord/snekbox-venv:latest
- displayName: 'Start Container'
-
- - script: |
- docker exec snekbox_test /bin/bash -c \
- 'pipenv install --system --deploy --dev'
- displayName: 'Install Development Dependencies'
diff --git a/docker-compose.yml b/docker-compose.yml
index aec17d3..066f38b 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -3,7 +3,7 @@ services:
snekbox:
container_name: snekbox
privileged: true
- image: pythondiscord/snekbox:latest
+ image: ghcr.io/python-discord/snekbox:latest
ports:
- 8060:8060
init: true
diff --git a/docker/Dockerfile b/docker/Dockerfile
index b6c2f77..ea05c5c 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -1,4 +1,60 @@
-FROM pythondiscord/snekbox-venv:latest
+FROM python:3.9-slim-buster as builder
+RUN apt-get -y update \
+ && apt-get install -y \
+ bison=2:3.3.* \
+ flex=2.6.* \
+ g++=4:8.3.* \
+ gcc=4:8.3.* \
+ git=1:2.20.* \
+ libprotobuf-dev=3.6.* \
+ libnl-route-3-dev=3.4.* \
+ make=4.2.* \
+ pkg-config=0.29-6 \
+ protobuf-compiler=3.6.*
+RUN git clone \
+ -b '2.9' \
+ --single-branch \
+ --depth 1 \
+ https://github.com/google/nsjail.git /nsjail
+WORKDIR /nsjail
+RUN make
+
+FROM python:3.9-slim-buster as base
+ENV PIP_NO_CACHE_DIR=false
+
+RUN apt-get -y update \
+ && apt-get install -y \
+ gcc=4:8.3.* \
+ libnl-route-3-200=3.4.* \
+ libprotobuf17=3.6.* \
+ && rm -rf /var/lib/apt/lists/*
+RUN pip install pipenv==2020.11.4
+
+COPY --from=builder /nsjail/nsjail /usr/sbin/
+RUN chmod +x /usr/sbin/nsjail
+
+FROM base as venv
+ARG DEV
+
+ENV PIP_NO_CACHE_DIR=false \
+ PIPENV_DONT_USE_PYENV=1 \
+ PIPENV_HIDE_EMOJIS=1 \
+ PIPENV_NOSPIN=1
+
+COPY Pipfile Pipfile.lock /snekbox/
+WORKDIR /snekbox
+
+RUN if [ -n "${DEV}" ]; \
+ then \
+ pipenv install --deploy --system --dev; \
+ else \
+ pipenv install --deploy --system; \
+ fi
+
+# At the end to avoid re-installing dependencies when only a config changes.
+COPY config/ /snekbox/config
+
+FROM venv
ENTRYPOINT ["gunicorn"]
CMD ["-c", "config/gunicorn.conf.py", "snekbox.api.app"]
diff --git a/docker/base.Dockerfile b/docker/base.Dockerfile
deleted file mode 100644
index a4a5ad1..0000000
--- a/docker/base.Dockerfile
+++ /dev/null
@@ -1,34 +0,0 @@
-FROM python:3.9-slim-buster as builder
-RUN apt-get -y update \
- && apt-get install -y \
- bison=2:3.3.* \
- flex=2.6.* \
- g++=4:8.3.* \
- gcc=4:8.3.* \
- git=1:2.20.* \
- libprotobuf-dev=3.6.* \
- libnl-route-3-dev=3.4.* \
- make=4.2.* \
- pkg-config=0.29-6 \
- protobuf-compiler=3.6.*
-RUN git clone \
- -b '2.9' \
- --single-branch \
- --depth 1 \
- https://github.com/google/nsjail.git /nsjail
-WORKDIR /nsjail
-RUN make
-
-FROM python:3.9-slim-buster
-ENV PIP_NO_CACHE_DIR=false
-
-RUN apt-get -y update \
- && apt-get install -y \
- gcc=4:8.3.* \
- libnl-route-3-200=3.4.* \
- libprotobuf17=3.6.* \
- && rm -rf /var/lib/apt/lists/*
-RUN pip install pipenv==2020.11.4
-
-COPY --from=builder /nsjail/nsjail /usr/sbin/
-RUN chmod +x /usr/sbin/nsjail
diff --git a/docker/venv.Dockerfile b/docker/venv.Dockerfile
deleted file mode 100644
index 5c0fcfc..0000000
--- a/docker/venv.Dockerfile
+++ /dev/null
@@ -1,20 +0,0 @@
-FROM pythondiscord/snekbox-base:latest
-
-ARG DEV
-ENV PIP_NO_CACHE_DIR=false \
- PIPENV_DONT_USE_PYENV=1 \
- PIPENV_HIDE_EMOJIS=1 \
- PIPENV_NOSPIN=1
-
-COPY Pipfile Pipfile.lock /snekbox/
-WORKDIR /snekbox
-
-RUN if [ -n "${DEV}" ]; \
- then \
- pipenv install --deploy --system --dev; \
- else \
- pipenv install --deploy --system; \
- fi
-
-# At the end to avoid re-installing dependencies when only a config changes.
-COPY config/ /snekbox/config
diff --git a/scripts/check_dockerfiles.sh b/scripts/check_dockerfiles.sh
deleted file mode 100755
index 88cb7cc..0000000
--- a/scripts/check_dockerfiles.sh
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-shopt -s inherit_errexit
-exec 3>&1 # New file descriptor to stdout
-
-BASE_URL="https://dev.azure.com/\
-python-discord/${SYSTEM_TEAMPROJECTID}/_apis/build/builds?\
-queryOrder=finishTimeDescending&\
-resultFilter=succeeded&\
-\$top=1&\
-repositoryType=${BUILD_REPOSITORY_PROVIDER}&\
-repositoryId=${BUILD_REPOSITORY_NAME}&\
-api-version=5.0"
-
-declare -A build_cache
-
-get_build() {
- local branch="${1:?"get_build: argument 1 'branch' is unset"}"
-
- # Attempt to use cached value
- if [[ -v build_cache["${branch}"] ]]; then
- printf '%s\n' "Retrieving build for ${branch} from cache." >&3
- printf '%s' "${build_cache[$branch]}"
- return 0
- fi
-
- local url="${BASE_URL}&branchName=${branch}"
-
- printf '%s\n' "Retrieving the latest successful build using ${url}" >&3
-
- local response
- response="$(curl -sSL "${url}")"
-
- if [[ -z "${response}" ]] \
- || ! count="$(printf '%s' "${response}" | jq -re '.count')" \
- || (( "${count}" < 1 ))
- then
- return 1
- else
- # Cache the response
- build_cache["${branch}"]="${response}"
- printf '%s' "${response}"
- fi
-}
-
-can_pull() {
- local image="${1:?"can_pull: argument 1 'image' is unset"}"
-
- local master_commit
- if master_commit="$(
- get_build "refs/heads/master" \
- | jq -re '.value[0].sourceVersion'
- )" \
- && git diff --quiet "${master_commit}" -- "${@:2}"
- then
- printf \
- '%s\n' \
- "Can pull ${image} image from Docker Hub; no changes since master."
-
- printf '%s\n' "##vso[task.setvariable variable=${image^^}_PULL]True"
- else
- printf \
- '%s\n' \
- "Cannot pull ${image} image from Docker Hub due to detected " \
- "changes; the ${image} image will be built."
-
- return 1
- fi
-}
-
-# Get the previous commit
-if [[ "${BUILD_REASON}" = "PullRequest" ]]; then
- if ! prev_commit="$(
- get_build "${BUILD_SOURCEBRANCH}" \
- | jq -re '.value[0].triggerInfo."pr.sourceSha"'
- )"
- then
- echo \
- "Could not retrieve the previous build's commit." \
- "Falling back to the head of the target branch."
-
- prev_commit="origin/${SYSTEM_PULLREQUEST_TARGETBRANCH}"
- fi
-elif ! prev_commit="$(
- get_build "${BUILD_SOURCEBRANCH}" \
- | jq -re '.value[0].sourceVersion'
- )"
-then
- echo \
- "No previous build was found." \
- "Either the previous build is too old and was deleted" \
- "or the branch was empty before this build." \
- "All images will be built."
- exit 0
-fi
-
-# Compare diffs
-head="$(git rev-parse HEAD)"
-printf '%s\n' "Comparing HEAD (${head}) against ${prev_commit}."
-
-if git diff --quiet "${prev_commit}" -- docker/base.Dockerfile; then
- echo "No changes detected in docker/base.Dockerfile."
- echo "##vso[task.setvariable variable=BASE_CHANGED]False"
-else
- # Always rebuild the venv if the base changes.
- echo "Changes detected in docker/base.Dockerfile; all images will be built."
- exit 0
-fi
-
-if git diff --quiet "${prev_commit}" -- docker/venv.Dockerfile Pipfile*; then
- echo "No changes detected in docker/venv.Dockerfile or the Pipfiles."
- echo "##vso[task.setvariable variable=VENV_CHANGED]False"
-
- if ! can_pull venv docker/venv.Dockerfile Pipfile*; then
- # Venv image can't be pulled so it needs to be built.
- # Therefore, the base image is needed too.
- can_pull base docker/base.Dockerfile || true
- fi
-else
- echo \
- "Changes detected in docker/venv.Dockerfile or the Pipfiles;" \
- "the venv image will be built."
-
- # Though base image hasn't changed, it's still needed to build the venv.
- can_pull base docker/base.Dockerfile || true
-fi
diff --git a/scripts/dev.sh b/scripts/dev.sh
index 408ce2e..f9fc016 100755
--- a/scripts/dev.sh
+++ b/scripts/dev.sh
@@ -5,12 +5,13 @@
if [ "$1" = "--build" ]; then
shift
- printf "Building pythondiscord/snekbox-venv:dev..."
+ printf "Building ghcr.io/python-discord/snekbox-venv:dev..."
docker build \
- -t pythondiscord/snekbox-venv:dev \
- -f docker/venv.Dockerfile \
+ -t ghcr.io/python-discord/snekbox-venv:dev \
+ -f docker/Dockerfile \
--build-arg DEV=1 \
+ --target venv \
-q \
. \
>/dev/null \
@@ -46,7 +47,7 @@ docker run \
--volume "${PWD}":"${PWD}" \
--workdir "${PWD}"\
--entrypoint /bin/bash \
- pythondiscord/snekbox-venv:dev \
+ ghcr.io/python-discord/snekbox-venv:dev \
>/dev/null \
# Execute the given command(s)