# https://aka.ms/yaml jobs: - job: test displayName: 'Lint & Test' pool: vmImage: 'ubuntu-16.04' steps: - task: ShellScript@2 displayName: 'Check If Images Need to Be Built' name: check inputs: scriptPath: scripts/check_dockerfiles.sh # Without a login the following Docker build tasks won't add image tags. - task: Docker@2 displayName: 'Log into Docker Hub' inputs: command: login containerRegistry: DockerHubV2 # 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. - task: Docker@2 displayName: 'Build Base Image' condition: and(succeeded(), ne(variables['check.BASE_PULL'], True)) inputs: command: build repository: pythondiscord/snekbox-base tags: latest Dockerfile: docker/base.Dockerfile buildContext: . # The dev image is never pushed and therefore is always built. - task: Docker@2 displayName: 'Build Development Image' inputs: command: build repository: pythondiscord/snekbox-venv tags: dev Dockerfile: docker/venv.Dockerfile buildContext: . arguments: --build-arg DEV=1 # 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/ash \ pythondiscord/snekbox-venv:dev displayName: 'Start Container' - script: | docker exec snekbox_test /bin/ash -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/ash -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/ash -c \ 'pipenv run /bin/ash -c "coverage report && coverage xml"' displayName: 'Generate Coverage Report' - task: PublishCodeCoverageResults@1 displayName: 'Publish Coverage Results' condition: succeededOrFailed() inputs: codeCoverageTool: Cobertura summaryFileLocation: '**/coverage.xml' # 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@2 displayName: 'Log into Docker Hub' inputs: command: login containerRegistry: DockerHubV2 # 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. - task: Docker@2 displayName: 'Build Base Image' condition: > and( succeeded(), ne(variables.BASE_PULL, True), or( eq(variables.BASE_CHANGED, True), eq(variables.VENV_CHANGED, True) ) ) inputs: command: build repository: pythondiscord/snekbox-base tags: latest Dockerfile: docker/base.Dockerfile buildContext: . # Also build this image if base has changed - even if this image hasn't. - task: Docker@2 displayName: 'Build Virtual Environment Image' condition: > and( succeeded(), or( eq(variables.BASE_CHANGED, True), eq(variables.VENV_CHANGED, True) ) ) inputs: command: build repository: pythondiscord/snekbox-venv tags: latest Dockerfile: docker/venv.Dockerfile buildContext: . # Always build this image unless it's for a pull request. - task: Docker@2 displayName: 'Build Final Image' condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) inputs: command: build repository: pythondiscord/snekbox tags: latest Dockerfile: docker/Dockerfile buildContext: . # 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. - task: Docker@2 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) ) ) inputs: command: push repository: pythondiscord/snekbox-base tags: latest - task: Docker@2 displayName: 'Push Virtual Environment Image' condition: > and( succeeded(), ne(variables['Build.Reason'], 'PullRequest'), or( eq(variables.BASE_CHANGED, True), eq(variables.VENV_CHANGED, True) ) ) inputs: command: push repository: pythondiscord/snekbox-venv tags: latest - task: Docker@2 displayName: 'Push Final Image' condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) inputs: command: push repository: pythondiscord/snekbox tags: latest