From 98057a2f292478fd3526dd033c6d3b37a23bd71b Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Mon, 16 Dec 2019 15:19:46 -0800 Subject: CI: always check if the base image can be pulled from Docker Hub --- scripts/check_dockerfiles.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/check_dockerfiles.sh b/scripts/check_dockerfiles.sh index c84c61f..c2a7d47 100755 --- a/scripts/check_dockerfiles.sh +++ b/scripts/check_dockerfiles.sh @@ -74,13 +74,17 @@ 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;isOutput=true]False" -elif master_commit="$( +fi + +# Though base image hasn't changed, it's still needed to build the venv. +# Even if the venv hasn't changed, the dev venv image is still needed to run +# the linter and tests. Therefore, the base image is also always needed. +if master_commit="$( get_build "refs/heads/master" \ | jq -re '.value[0].sourceVersion' )" \ && git diff --quiet "${master_commit}" -- docker/base.Dockerfile then - # Though base image hasn't changed, it's still needed to build the venv. echo "Can pull base image from Docker Hub; no changes made since master." echo "##vso[task.setvariable variable=BASE_PULL;isOutput=true]True" fi -- cgit v1.2.3 From 80985b144d0afb2c6e06de0b66e9e54fb9421410 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Mon, 16 Dec 2019 15:27:32 -0800 Subject: CI: add more logging in check_dockerfiles.sh --- scripts/check_dockerfiles.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scripts/check_dockerfiles.sh b/scripts/check_dockerfiles.sh index c2a7d47..b1f0e28 100755 --- a/scripts/check_dockerfiles.sh +++ b/scripts/check_dockerfiles.sh @@ -68,12 +68,17 @@ if git diff --quiet "${prev_commit}" -- docker/base.Dockerfile; then echo "##vso[task.setvariable variable=BASE_CHANGED;isOutput=true]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;isOutput=true]False" +else + echo \ + "Changes detected in docker/venv.Dockerfile or the Pipfiles;" \ + "the venv image will be built." fi # Though base image hasn't changed, it's still needed to build the venv. @@ -87,4 +92,8 @@ if master_commit="$( then echo "Can pull base image from Docker Hub; no changes made since master." echo "##vso[task.setvariable variable=BASE_PULL;isOutput=true]True" +else + echo \ + "Cannot pull base image from Docker Hub due to detected changes;" \ + "the base image will be built." fi -- cgit v1.2.3 From fde1bfc72388672588941c595fb768ddbfa76ac9 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Mon, 16 Dec 2019 15:34:49 -0800 Subject: CI: update agent to Ubuntu 18.04 * Use inherit_errexit in check_dockerfiles.sh --- azure-pipelines.yml | 2 +- scripts/check_dockerfiles.sh | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3559031..c5f033d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -5,7 +5,7 @@ jobs: displayName: 'Lint & Test' pool: - vmImage: 'ubuntu-16.04' + vmImage: 'ubuntu-18.04' steps: - task: ShellScript@2 diff --git a/scripts/check_dockerfiles.sh b/scripts/check_dockerfiles.sh index b1f0e28..53842e2 100755 --- a/scripts/check_dockerfiles.sh +++ b/scripts/check_dockerfiles.sh @@ -1,6 +1,7 @@ #!/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/\ @@ -13,8 +14,6 @@ repositoryId=${BUILD_REPOSITORY_NAME}&\ api-version=5.0" get_build() { - set -e # Poor Ubuntu LTS doesn't have Bash 4.4's inherit_errexit - local branch="${1:?"get_build: argument 1 'branch' is unset"}" local url="${BASE_URL}&branchName=${branch}" -- cgit v1.2.3 From ddaf1c29366399a61ae9aa1678293e342079f23f Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Fri, 21 Feb 2020 17:35:12 -0800 Subject: CI: move lint & tests job into templates Splitting steps into several files makes the YAML more maintainable. --- azure-pipelines.yml | 96 ++--------------------------------------------------- ci/build.yml | 35 +++++++++++++++++++ ci/lint-test.yml | 41 +++++++++++++++++++++++ ci/setup.yml | 18 ++++++++++ 4 files changed, 97 insertions(+), 93 deletions(-) create mode 100644 ci/build.yml create mode 100644 ci/lint-test.yml create mode 100644 ci/setup.yml diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c5f033d..1ccc04e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -8,99 +8,9 @@ jobs: vmImage: 'ubuntu-18.04' steps: - - task: ShellScript@2 - displayName: 'Check If Images Need to Be Built' - name: check - inputs: - scriptPath: scripts/check_dockerfiles.sh - disableAutoCwd: true - - # Without a login the following Docker build tasks won't add image tags. - - task: Docker@1 - displayName: 'Log into Docker Hub' - inputs: - command: login - containerregistrytype: 'Container Registry' - dockerRegistryEndpoint: 'DockerHub' - - # The venv image depends on this image. Build it if it can't be pulled - # from Docker Hub, which will be the case if the base Dockerfile has had - # changes. - - script: | - docker build \ - -f docker/base.Dockerfile \ - -t pythondiscord/snekbox-base:latest \ - . - displayName: 'Build Base Image' - condition: and(succeeded(), ne(variables['check.BASE_PULL'], True)) - - # The dev image is never pushed and therefore is always built. - - script: | - docker build \ - -f docker/venv.Dockerfile \ - -t pythondiscord/snekbox-venv:dev \ - --build-arg DEV=1 \ - . - displayName: 'Build Development Image' - - # The linter and all tests run inside this container. - - script: | - docker run \ - --tty \ - --detach \ - --name snekbox_test \ - --privileged \ - --network host \ - --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:dev - displayName: 'Start Container' - - - script: | - docker exec snekbox_test /bin/bash -c \ - 'pipenv run lint --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 \ - 'pipenv run 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 \ - 'pipenv run /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' + - template: ci/build.yml + - template: ci/setup.yml + - template: ci/lint-test.yml # When a pull request, only perform this job if images need to be built. # It's always performed for non-PRs because the final image will always need diff --git a/ci/build.yml b/ci/build.yml new file mode 100644 index 0000000..139203e --- /dev/null +++ b/ci/build.yml @@ -0,0 +1,35 @@ +steps: + - task: ShellScript@2 + displayName: 'Check If Images Need to Be Built' + name: check + inputs: + scriptPath: scripts/check_dockerfiles.sh + disableAutoCwd: true + + # Without a login the following Docker build tasks won't add image tags. + - task: Docker@1 + displayName: 'Log into Docker Hub' + inputs: + command: login + containerregistrytype: 'Container Registry' + dockerRegistryEndpoint: 'DockerHub' + + # The venv image depends on this image. Build it if it can't be pulled + # from Docker Hub, which will be the case if the base Dockerfile has had + # changes. + - script: | + docker build \ + -f docker/base.Dockerfile \ + -t pythondiscord/snekbox-base:latest \ + . + displayName: 'Build Base Image' + condition: and(succeeded(), ne(variables['check.BASE_PULL'], True)) + + # The dev image is never pushed and therefore is always built. + - script: | + docker build \ + -f docker/venv.Dockerfile \ + -t pythondiscord/snekbox-venv:dev \ + --build-arg DEV=1 \ + . + displayName: 'Build Development Image' diff --git a/ci/lint-test.yml b/ci/lint-test.yml new file mode 100644 index 0000000..3c3eae6 --- /dev/null +++ b/ci/lint-test.yml @@ -0,0 +1,41 @@ +steps: + - script: | + docker exec snekbox_test /bin/bash -c \ + 'pipenv run lint --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 \ + 'pipenv run 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 \ + 'pipenv run /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/setup.yml b/ci/setup.yml new file mode 100644 index 0000000..25530e7 --- /dev/null +++ b/ci/setup.yml @@ -0,0 +1,18 @@ +steps: + # The linter and all tests run inside this container. + - script: | + docker run \ + --tty \ + --detach \ + --name snekbox_test \ + --privileged \ + --network host \ + --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:dev + displayName: 'Start Container' -- cgit v1.2.3 From 034e9a062071affdec3ee9f54bbfddb04a2f4b5c Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Fri, 21 Feb 2020 17:48:47 -0800 Subject: CI: diff base against master only if venv changed --- scripts/check_dockerfiles.sh | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/scripts/check_dockerfiles.sh b/scripts/check_dockerfiles.sh index 53842e2..b3b5fe2 100755 --- a/scripts/check_dockerfiles.sh +++ b/scripts/check_dockerfiles.sh @@ -78,21 +78,19 @@ else echo \ "Changes detected in docker/venv.Dockerfile or the Pipfiles;" \ "the venv image will be built." -fi -# Though base image hasn't changed, it's still needed to build the venv. -# Even if the venv hasn't changed, the dev venv image is still needed to run -# the linter and tests. Therefore, the base image is also always needed. -if master_commit="$( - get_build "refs/heads/master" \ - | jq -re '.value[0].sourceVersion' - )" \ - && git diff --quiet "${master_commit}" -- docker/base.Dockerfile -then - echo "Can pull base image from Docker Hub; no changes made since master." - echo "##vso[task.setvariable variable=BASE_PULL;isOutput=true]True" -else - echo \ - "Cannot pull base image from Docker Hub due to detected changes;" \ - "the base image will be built." + # Though base image hasn't changed, it's still needed to build the venv. + if master_commit="$( + get_build "refs/heads/master" \ + | jq -re '.value[0].sourceVersion' + )" \ + && git diff --quiet "${master_commit}" -- docker/base.Dockerfile + then + echo "Can pull base image from Docker Hub; no changes since master." + echo "##vso[task.setvariable variable=BASE_PULL;isOutput=true]True" + else + echo \ + "Cannot pull base image from Docker Hub due to detected changes;" \ + "the base image will be built." + fi fi -- cgit v1.2.3 From 8b4938cb925a550d587867cf50d2d98df06d9f72 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Fri, 21 Feb 2020 18:05:20 -0800 Subject: CI: install dev dependencies inside running container This change allows for the venv image to be pushed since it won't be built with dev dependencies. --- ci/build.yml | 16 ++++++++-------- ci/setup.yml | 8 +++++++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/ci/build.yml b/ci/build.yml index 139203e..fcde2e1 100644 --- a/ci/build.yml +++ b/ci/build.yml @@ -6,7 +6,7 @@ steps: scriptPath: scripts/check_dockerfiles.sh disableAutoCwd: true - # Without a login the following Docker build tasks won't add image tags. + # Without a login, the following Docker build steps wouldn't add image tags. - task: Docker@1 displayName: 'Log into Docker Hub' inputs: @@ -14,9 +14,9 @@ steps: containerregistrytype: 'Container Registry' dockerRegistryEndpoint: 'DockerHub' - # The venv image depends on this image. Build it if it can't be pulled - # from Docker Hub, which will be the case if the base Dockerfile has had - # changes. + # 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 \ @@ -25,11 +25,11 @@ steps: displayName: 'Build Base Image' condition: and(succeeded(), ne(variables['check.BASE_PULL'], True)) - # The dev image is never pushed and therefore is always built. + # Build the venv image if it's had changes. - script: | docker build \ -f docker/venv.Dockerfile \ - -t pythondiscord/snekbox-venv:dev \ - --build-arg DEV=1 \ + -t pythondiscord/snekbox-venv:latest \ . - displayName: 'Build Development Image' + displayName: 'Build Virtual Environment Image' + condition: and(succeeded(), ne(variables['check.VENV_CHANGED'], False)) diff --git a/ci/setup.yml b/ci/setup.yml index 25530e7..cf190de 100644 --- a/ci/setup.yml +++ b/ci/setup.yml @@ -1,5 +1,6 @@ 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 \ @@ -14,5 +15,10 @@ steps: --volume "${PWD}":"${PWD}" \ --workdir "${PWD}"\ --entrypoint /bin/bash \ - pythondiscord/snekbox-venv:dev + pythondiscord/snekbox-venv:latest displayName: 'Start Container' + + - script: | + docker exec snekbox_test /bin/bash -c \ + 'pipenv install --system --deploy --dev' + displayName: 'Install Development Dependencies' -- cgit v1.2.3 From 686419d1b1d4c6457819ecf2306a36278fe66f55 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Fri, 21 Feb 2020 18:21:29 -0800 Subject: CI: compare variables against strings Avoids type casting ambiguity and weirdness. --- azure-pipelines.yml | 30 +++++++++++++++--------------- ci/build.yml | 4 ++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1ccc04e..9b0c648 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,17 +22,17 @@ jobs: succeeded(), or( ne(variables['Build.Reason'], 'PullRequest'), - eq(coalesce(dependencies.test.outputs['check.BASE_CHANGED'], True), True), - eq(coalesce(dependencies.test.outputs['check.VENV_CHANGED'], True), True) + eq(coalesce(dependencies.test.outputs['check.BASE_CHANGED'], 'True'), 'True'), + eq(coalesce(dependencies.test.outputs['check.VENV_CHANGED'], 'True'), 'True') ) ) dependsOn: test # coalesce() gives variables default values if they are null (i.e. unset). variables: - BASE_CHANGED: $[ coalesce(dependencies.test.outputs['check.BASE_CHANGED'], True) ] - VENV_CHANGED: $[ coalesce(dependencies.test.outputs['check.VENV_CHANGED'], True) ] - BASE_PULL: $[ coalesce(dependencies.test.outputs['check.BASE_PULL'], False) ] + BASE_CHANGED: $[ coalesce(dependencies.test.outputs['check.BASE_CHANGED'], 'True') ] + VENV_CHANGED: $[ coalesce(dependencies.test.outputs['check.VENV_CHANGED'], 'True') ] + BASE_PULL: $[ coalesce(dependencies.test.outputs['check.BASE_PULL'], 'False') ] steps: - task: Docker@1 @@ -54,10 +54,10 @@ jobs: condition: > and( succeeded(), - ne(variables.BASE_PULL, True), + ne(variables.BASE_PULL, 'True'), or( - eq(variables.BASE_CHANGED, True), - eq(variables.VENV_CHANGED, True) + eq(variables.BASE_CHANGED, 'True'), + eq(variables.VENV_CHANGED, 'True') ) ) @@ -72,8 +72,8 @@ jobs: and( succeeded(), or( - eq(variables.BASE_CHANGED, True), - eq(variables.VENV_CHANGED, True) + eq(variables.BASE_CHANGED, 'True'), + eq(variables.VENV_CHANGED, 'True') ) ) @@ -95,10 +95,10 @@ jobs: and( succeeded(), ne(variables['Build.Reason'], 'PullRequest'), - ne(variables.BASE_PULL, True), + ne(variables.BASE_PULL, 'True'), or( - eq(variables.BASE_CHANGED, True), - eq(variables.VENV_CHANGED, True) + eq(variables.BASE_CHANGED, 'True'), + eq(variables.VENV_CHANGED, 'True') ) ) @@ -109,8 +109,8 @@ jobs: succeeded(), ne(variables['Build.Reason'], 'PullRequest'), or( - eq(variables.BASE_CHANGED, True), - eq(variables.VENV_CHANGED, True) + eq(variables.BASE_CHANGED, 'True'), + eq(variables.VENV_CHANGED, 'True') ) ) diff --git a/ci/build.yml b/ci/build.yml index fcde2e1..aa08436 100644 --- a/ci/build.yml +++ b/ci/build.yml @@ -23,7 +23,7 @@ steps: -t pythondiscord/snekbox-base:latest \ . displayName: 'Build Base Image' - condition: and(succeeded(), ne(variables['check.BASE_PULL'], True)) + condition: and(succeeded(), ne(variables['check.BASE_PULL'], 'True')) # Build the venv image if it's had changes. - script: | @@ -32,4 +32,4 @@ steps: -t pythondiscord/snekbox-venv:latest \ . displayName: 'Build Virtual Environment Image' - condition: and(succeeded(), ne(variables['check.VENV_CHANGED'], False)) + condition: and(succeeded(), ne(variables['check.VENV_CHANGED'], 'False')) -- cgit v1.2.3 From f1d428785c5948cfb634e8b8c4783f4a26bc7039 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Fri, 21 Feb 2020 18:32:15 -0800 Subject: CI: don't use output variables It was initially used to enable access to variables across jobs, but the jobs will eventually be consolidated into one so output variables will no longer be needed. --- ci/build.yml | 5 ++--- scripts/check_dockerfiles.sh | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ci/build.yml b/ci/build.yml index aa08436..a076431 100644 --- a/ci/build.yml +++ b/ci/build.yml @@ -1,7 +1,6 @@ steps: - task: ShellScript@2 displayName: 'Check If Images Need to Be Built' - name: check inputs: scriptPath: scripts/check_dockerfiles.sh disableAutoCwd: true @@ -23,7 +22,7 @@ steps: -t pythondiscord/snekbox-base:latest \ . displayName: 'Build Base Image' - condition: and(succeeded(), ne(variables['check.BASE_PULL'], 'True')) + condition: and(succeeded(), ne(variables.BASE_PULL, 'True')) # Build the venv image if it's had changes. - script: | @@ -32,4 +31,4 @@ steps: -t pythondiscord/snekbox-venv:latest \ . displayName: 'Build Virtual Environment Image' - condition: and(succeeded(), ne(variables['check.VENV_CHANGED'], 'False')) + condition: and(succeeded(), ne(variables.VENV_CHANGED, 'False')) diff --git a/scripts/check_dockerfiles.sh b/scripts/check_dockerfiles.sh index b3b5fe2..a0294b1 100755 --- a/scripts/check_dockerfiles.sh +++ b/scripts/check_dockerfiles.sh @@ -64,7 +64,7 @@ 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;isOutput=true]False" + 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." @@ -73,7 +73,7 @@ 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;isOutput=true]False" + echo "##vso[task.setvariable variable=VENV_CHANGED]False" else echo \ "Changes detected in docker/venv.Dockerfile or the Pipfiles;" \ @@ -87,7 +87,7 @@ else && git diff --quiet "${master_commit}" -- docker/base.Dockerfile then echo "Can pull base image from Docker Hub; no changes since master." - echo "##vso[task.setvariable variable=BASE_PULL;isOutput=true]True" + echo "##vso[task.setvariable variable=BASE_PULL]True" else echo \ "Cannot pull base image from Docker Hub due to detected changes;" \ -- cgit v1.2.3 From e64fd05168f61440047436cbe41d04c8070fdd9a Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Fri, 21 Feb 2020 18:33:00 -0800 Subject: CI: define default values for variables --- azure-pipelines.yml | 5 +++++ ci/build.yml | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9b0c648..a1a7a4f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,6 +7,11 @@ jobs: pool: vmImage: 'ubuntu-18.04' + variables: + BASE_CHANGED: 'True' + VENV_CHANGED: 'True' + BASE_PULL: 'False' + steps: - template: ci/build.yml - template: ci/setup.yml diff --git a/ci/build.yml b/ci/build.yml index a076431..6e71a00 100644 --- a/ci/build.yml +++ b/ci/build.yml @@ -22,7 +22,7 @@ steps: -t pythondiscord/snekbox-base:latest \ . displayName: 'Build Base Image' - condition: and(succeeded(), ne(variables.BASE_PULL, 'True')) + condition: and(succeeded(), eq(variables.BASE_PULL, 'False')) # Build the venv image if it's had changes. - script: | @@ -31,4 +31,4 @@ steps: -t pythondiscord/snekbox-venv:latest \ . displayName: 'Build Virtual Environment Image' - condition: and(succeeded(), ne(variables.VENV_CHANGED, 'False')) + condition: and(succeeded(), eq(variables.VENV_CHANGED, 'True')) -- cgit v1.2.3 From 908383a1d054ed9aa8559c83f0806f82bab71a16 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Fri, 21 Feb 2020 18:55:09 -0800 Subject: CI: fix base image build condition Build if the base changed or the venv changed and the base cannot be pulled. --- ci/build.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ci/build.yml b/ci/build.yml index 6e71a00..c5c4b43 100644 --- a/ci/build.yml +++ b/ci/build.yml @@ -22,7 +22,17 @@ steps: -t pythondiscord/snekbox-base:latest \ . displayName: 'Build Base Image' - condition: and(succeeded(), eq(variables.BASE_PULL, 'False')) + 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. - script: | -- cgit v1.2.3 From ed43d568651fc6c68e7aebd95680486ee95bc6f4 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Fri, 21 Feb 2020 21:25:31 -0800 Subject: CI: create a function to check if an image can be pulled --- scripts/check_dockerfiles.sh | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/scripts/check_dockerfiles.sh b/scripts/check_dockerfiles.sh index a0294b1..f2b8512 100755 --- a/scripts/check_dockerfiles.sh +++ b/scripts/check_dockerfiles.sh @@ -32,6 +32,31 @@ get_build() { 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="$( @@ -80,17 +105,5 @@ else "the venv image will be built." # Though base image hasn't changed, it's still needed to build the venv. - if master_commit="$( - get_build "refs/heads/master" \ - | jq -re '.value[0].sourceVersion' - )" \ - && git diff --quiet "${master_commit}" -- docker/base.Dockerfile - then - echo "Can pull base image from Docker Hub; no changes since master." - echo "##vso[task.setvariable variable=BASE_PULL]True" - else - echo \ - "Cannot pull base image from Docker Hub due to detected changes;" \ - "the base image will be built." - fi + can_pull base docker/base.Dockerfile fi -- cgit v1.2.3 From 9e0b6e6f98ce0bf728dc12a5157a7fa273c62e62 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Fri, 21 Feb 2020 21:55:37 -0800 Subject: CI: check if venv image can be pulled --- scripts/check_dockerfiles.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/check_dockerfiles.sh b/scripts/check_dockerfiles.sh index f2b8512..df6049e 100755 --- a/scripts/check_dockerfiles.sh +++ b/scripts/check_dockerfiles.sh @@ -99,6 +99,12 @@ 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 + fi else echo \ "Changes detected in docker/venv.Dockerfile or the Pipfiles;" \ -- cgit v1.2.3 From 59bccff36d11e6a38cd5ffb0ffa4f39acf9aad5d Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Fri, 21 Feb 2020 22:07:30 -0800 Subject: CI: don't build venv image if it can be pulled --- azure-pipelines.yml | 1 + ci/build.yml | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a1a7a4f..615d3a8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -11,6 +11,7 @@ jobs: BASE_CHANGED: 'True' VENV_CHANGED: 'True' BASE_PULL: 'False' + VENV_PULL: 'False' steps: - template: ci/build.yml diff --git a/ci/build.yml b/ci/build.yml index c5c4b43..7d51709 100644 --- a/ci/build.yml +++ b/ci/build.yml @@ -34,11 +34,18 @@ steps: ) ) - # Build the venv image if it's had changes. + # 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(), eq(variables.VENV_CHANGED, 'True')) + condition: > + and( + succeeded(), + or( + eq(variables.VENV_CHANGED, 'True'), + eq(variables.VENV_PULL, 'False') + ) + ) -- cgit v1.2.3 From 604e80a64e1ded4c002ff5a6ae89ceb329f5a120 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Fri, 21 Feb 2020 22:22:18 -0800 Subject: CI: merge build job with test job * Remove duplicate build steps * Move push steps to a separate YAML file --- azure-pipelines.yml | 111 ++-------------------------------------------------- ci/push.yml | 39 ++++++++++++++++++ 2 files changed, 42 insertions(+), 108 deletions(-) create mode 100644 ci/push.yml diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 615d3a8..c45550c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,8 +1,8 @@ # https://aka.ms/yaml jobs: - - job: test - displayName: 'Lint & Test' + - job: build-lint-test-push + displayName: 'Build, Lint, Test, & Push' pool: vmImage: 'ubuntu-18.04' @@ -17,109 +17,4 @@ jobs: - template: ci/build.yml - template: ci/setup.yml - template: ci/lint-test.yml - - # When a pull request, only perform this job if images need to be built. - # It's always performed for non-PRs because the final image will always need - # to be built. - - job: build - displayName: 'Build' - condition: > - and( - succeeded(), - or( - ne(variables['Build.Reason'], 'PullRequest'), - eq(coalesce(dependencies.test.outputs['check.BASE_CHANGED'], 'True'), 'True'), - eq(coalesce(dependencies.test.outputs['check.VENV_CHANGED'], 'True'), 'True') - ) - ) - dependsOn: test - - # coalesce() gives variables default values if they are null (i.e. unset). - variables: - BASE_CHANGED: $[ coalesce(dependencies.test.outputs['check.BASE_CHANGED'], 'True') ] - VENV_CHANGED: $[ coalesce(dependencies.test.outputs['check.VENV_CHANGED'], 'True') ] - BASE_PULL: $[ coalesce(dependencies.test.outputs['check.BASE_PULL'], 'False') ] - - steps: - - task: Docker@1 - displayName: 'Log into Docker Hub' - inputs: - command: login - containerregistrytype: 'Container Registry' - dockerRegistryEndpoint: 'DockerHub' - - # Because this is the base image for the venv image, if the venv needs to - # be built, this base image must also be present. Build it if it has - # changed or can't be pulled from Docker Hub. - - script: | - docker build \ - -f docker/base.Dockerfile \ - -t pythondiscord/snekbox-base:latest \ - . - displayName: 'Build Base Image' - condition: > - and( - succeeded(), - ne(variables.BASE_PULL, 'True'), - or( - eq(variables.BASE_CHANGED, 'True'), - eq(variables.VENV_CHANGED, 'True') - ) - ) - - # Also build this image if base has changed - even if this image hasn't. - - script: | - docker build \ - -f docker/venv.Dockerfile \ - -t pythondiscord/snekbox-venv:latest \ - . - displayName: 'Build Virtual Environment Image' - condition: > - and( - succeeded(), - or( - eq(variables.BASE_CHANGED, 'True'), - eq(variables.VENV_CHANGED, 'True') - ) - ) - - # 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. - # These have the same conditions as the build tasks. However, for safety, - # a condition for not being a pull request is added. - - 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')) + - template: ci/push.yml diff --git a/ci/push.yml b/ci/push.yml new file mode 100644 index 0000000..9449df0 --- /dev/null +++ b/ci/push.yml @@ -0,0 +1,39 @@ +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')) -- cgit v1.2.3 From 5c032bd7b4d69afe054f6f43d14a5185ca3a4c9d Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Fri, 21 Feb 2020 22:43:04 -0800 Subject: CI: fix job name Hyphens are disallowed so they are replaced with underscores. --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c45550c..573e3cc 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,7 +1,7 @@ # https://aka.ms/yaml jobs: - - job: build-lint-test-push + - job: build_lint_test_push displayName: 'Build, Lint, Test, & Push' pool: -- cgit v1.2.3 From 57cf063c0dfa6935088e96549d224ff50f56011f Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Sat, 22 Feb 2020 20:16:53 -0800 Subject: CI: cache the response from Azure API The script may need to use the master commit several times. The easiest way to implement the cache was to just cache the response rather than the commit hash. --- scripts/check_dockerfiles.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/scripts/check_dockerfiles.sh b/scripts/check_dockerfiles.sh index df6049e..1764017 100755 --- a/scripts/check_dockerfiles.sh +++ b/scripts/check_dockerfiles.sh @@ -13,8 +13,17 @@ 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' "${build_cache[$branch]}" + return 0 + fi + local url="${BASE_URL}&branchName=${branch}" printf '%s\n' "Retrieving the latest successful build using ${url}" >&3 @@ -28,6 +37,8 @@ get_build() { then return 1 else + # Cache the response + build_cache["${branch}"]="${response}" printf '%s' "${response}" fi } -- cgit v1.2.3 From 9cf62966c410acaf6912a2ecca75e82f07ea6937 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Sat, 22 Feb 2020 20:49:17 -0800 Subject: CI: fix unbound variable error when checking cache The array shouldn't be expanded when testing with -v. --- scripts/check_dockerfiles.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check_dockerfiles.sh b/scripts/check_dockerfiles.sh index 1764017..a94ccb4 100755 --- a/scripts/check_dockerfiles.sh +++ b/scripts/check_dockerfiles.sh @@ -19,7 +19,7 @@ get_build() { local branch="${1:?"get_build: argument 1 'branch' is unset"}" # Attempt to use cached value - if [[ -v "${build_cache[$branch]}" ]]; then + if [[ -v build_cache["${branch}"] ]]; then printf '%s' "${build_cache[$branch]}" return 0 fi -- cgit v1.2.3 From 736f9b1587061bbbabacb4ee65dc3b4989887d75 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Sat, 22 Feb 2020 20:54:08 -0800 Subject: CI: log when the build cache is used --- scripts/check_dockerfiles.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/check_dockerfiles.sh b/scripts/check_dockerfiles.sh index a94ccb4..95c18cb 100755 --- a/scripts/check_dockerfiles.sh +++ b/scripts/check_dockerfiles.sh @@ -20,6 +20,7 @@ get_build() { # 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 -- cgit v1.2.3 From 01abcb67ef3efc52edcfa302377137b46007287f Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Sat, 22 Feb 2020 21:24:52 -0800 Subject: CI: don't run commands through pipenv Since #62, the dependencies have been installed to the system interpreter. Therefore, it's not necessary to run through pipenv to ensure the commands run through an activated virtual environment. This should also fix pipenv run creating a virtual environment. It seems it cannot tell when it should be using the system interpreter. It probably wasn't designed for that anyway i.e. the intent was to run commands directly in such case, which is what this PR will do. --- ci/lint-test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/lint-test.yml b/ci/lint-test.yml index 3c3eae6..6350fde 100644 --- a/ci/lint-test.yml +++ b/ci/lint-test.yml @@ -1,7 +1,7 @@ steps: - script: | docker exec snekbox_test /bin/bash -c \ - 'pipenv run lint --format junit-xml --output-file test-lint.xml' + 'flake8 --format junit-xml --output-file test-lint.xml' displayName: 'Run Linter' - task: PublishTestResults@2 @@ -17,7 +17,7 @@ steps: - script: | docker exec snekbox_test /bin/bash -c \ - 'pipenv run coverage run -m xmlrunner' + 'coverage run -m xmlrunner' displayName: 'Run Unit Tests' - task: PublishTestResults@2 @@ -30,7 +30,7 @@ steps: # Run report too because the XML report doesn't output to stdout. - script: | docker exec snekbox_test /bin/bash -c \ - 'pipenv run /bin/bash -c "coverage report && coverage xml"' + 'coverage report && coverage xml' displayName: 'Generate Coverage Report' - task: PublishCodeCoverageResults@1 -- cgit v1.2.3 From 692c75a470682a97947bcd060b153ed757626805 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Sat, 22 Feb 2020 21:32:41 -0800 Subject: CI: output flake8 to stdout (resolve #37) The Azure website has proven to not be reliable for displaying the JUnit output. Furthermore, some may simply prefer the format of the output in the terminal over the JUnit representation on the Azure site. Nevertheless, the JUnit output isn't that bad (when there's actually a lint error) so it will remain for now. It also provides historical statistics on occurrences of errors, which is kind of cool, I guess... --- ci/lint-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/lint-test.yml b/ci/lint-test.yml index 6350fde..2d70f6e 100644 --- a/ci/lint-test.yml +++ b/ci/lint-test.yml @@ -1,7 +1,7 @@ steps: - script: | docker exec snekbox_test /bin/bash -c \ - 'flake8 --format junit-xml --output-file test-lint.xml' + 'flake8; flake8 --format junit-xml --output-file test-lint.xml' displayName: 'Run Linter' - task: PublishTestResults@2 -- cgit v1.2.3