371 lines
14 KiB
YAML
371 lines
14 KiB
YAML
---
|
|
version: '3'
|
|
|
|
vars:
|
|
DIND_MOUNT_MAPPING: /var/run/docker.sock:/var/run/docker.sock
|
|
DOCKER_BASE_TAG:
|
|
sh: |
|
|
if [ -f Dockerfile ] && type jq &> /dev/null; then
|
|
BASE_TAG="$(jq -r '.blueprint.dockerBaseTag' package.json)"
|
|
if [ "$BASE_TAG" != 'null' ]; then
|
|
echo "$BASE_TAG"
|
|
else
|
|
if grep -m1 "^FROM .* AS .*" Dockerfile > /dev/null; then
|
|
FIRST_LINE=$(head -n 1 Dockerfile | sed 's/.* AS \(.*\)/\1/')
|
|
if [ -n "$FIRST_LINE" ]; then
|
|
echo "$FIRST_LINE"
|
|
else
|
|
echo ""
|
|
fi
|
|
else
|
|
echo ""
|
|
fi
|
|
fi
|
|
fi
|
|
DOCKER_IMAGE:
|
|
sh: |
|
|
if type jq &> /dev/null; then
|
|
echo "{{.DOCKERHUB_PROFILE}}/$(jq -r '.blueprint.slug' package.json)"
|
|
fi
|
|
|
|
tasks:
|
|
build:
|
|
desc: Build a regular Docker image and then generate a slim build from it
|
|
summary: |
|
|
# Build the Docker Images
|
|
|
|
This task will build all of the corresponding Docker images as long as they
|
|
have a [container-structure-test](https://github.com/GoogleContainerTools/container-structure-test)
|
|
created.
|
|
|
|
For regular projects, having a `Docker.test.yml` container-structure-test is enough. However,
|
|
for projects with multiple build targets, there should be a test for each target. So, if there
|
|
are 2 build targets in the `Dockerfile` named `build1` and `build2` then there should be
|
|
a `Docker.build1.test.yml` and `Docker.build2.test.yml` container-structure-test.
|
|
hide:
|
|
sh: '[ ! -f Dockerfile ]'
|
|
log:
|
|
error: Encountered error while running Docker build sequence
|
|
start: Running Docker build sequence
|
|
success: Finished running Docker build sequence
|
|
cmds:
|
|
- task: ensure:running
|
|
- task: taskfile:deps
|
|
- |
|
|
if [ -d ./test/structure ]; then
|
|
TESTS="$(find ./test/structure -mindepth 1 -maxdepth 1 -type f -name "*.yml")"
|
|
if echo "$TESTS" | grep '.yml' > /dev/null; then
|
|
for TEST_FILE in $TESTS; do
|
|
TARGET="$(echo "$TEST_FILE" | sed 's/.*\/\([^\/]*\).yml$/\1/')"
|
|
if [ "$(jq --arg slug "$TARGET" '.blueprint.dockerSlimCommand | type' package.json)" == 'object' ]; then
|
|
if [ "$(jq --arg slug "$TARGET" '.blueprint.dockerSlimCommand[$slug]' package.json)" != 'null' ]; then
|
|
task docker:build:slim -- "$TARGET"
|
|
else
|
|
.config/log warn 'The `.blueprint.dockerSlimCommand` is missing - skipping slim build and building just a regular image'
|
|
task docker:build:fat -- "$TARGET"
|
|
fi
|
|
else
|
|
if [ "$(jq --arg slug "$TARGET" '.blueprint.dockerSlimCommand' package.json)" != 'null' ]; then
|
|
task docker:build:slim -- "$TARGET"
|
|
else
|
|
task docker:build:fat -- "$TARGET"
|
|
fi
|
|
fi
|
|
done
|
|
else
|
|
.config/log error 'The `./test/structure` folder is present but there are no container-structure-tests in it. Add tests \
|
|
for each build target in the `Dockerfile` that you would like to generate an image for.'
|
|
exit 1
|
|
fi
|
|
else
|
|
.config/log info 'No `./test/structure` folder is present so assuming there is only one build target'
|
|
if [ "$(jq -r '.blueprint.dockerSlimCommand' package.json)" != null ]; then
|
|
.config/log info '`.blueprint.dockerSlimCommand` is present in `package.json` so building both a `latest` and `slim` image'
|
|
task docker:build:slim
|
|
else
|
|
task docker:build:fat
|
|
fi
|
|
fi
|
|
|
|
ensure:running:
|
|
summary: |
|
|
Ensures Docker Desktop is running if on a macOS machine.
|
|
cmds:
|
|
- |
|
|
if ! docker stats --no-stream; then
|
|
if [ -f /Applications/Docker.app ]; then
|
|
open /Applications/Docker.app
|
|
while (! docker stats --no-stream); do
|
|
echo "Waiting for Docker to launch..."
|
|
sleep 1
|
|
done
|
|
else
|
|
.config/log error 'Docker is either not running or not installed!'
|
|
fi
|
|
fi
|
|
status:
|
|
- '[[ "{{OS}}" != "darwin" ]]'
|
|
|
|
login:
|
|
deps:
|
|
- :install:software:docker
|
|
log:
|
|
error: Failed to authenticate `{{.DOCKERHUB_USER}}` with the DockerHub registry
|
|
start: Logging into DockerHub registry with `{{.DOCKERHUB_USER}}`
|
|
success: Authenticated to DockerHub registry with `{{.DOCKERHUB_USER}}`
|
|
cmds:
|
|
- |
|
|
if [ -n "$DOCKERHUB_REGISTRY_PASSWORD" ]; then
|
|
echo "$DOCKERHUB_REGISTRY_PASSWORD" | docker login -u {{.DOCKERHUB_USER}} --password-stdin
|
|
else
|
|
.config/log warn 'The `DOCKERHUB_REGISTRY_PASSWORD` is not an environment variable. This is required to login to DockerHub.'
|
|
fi
|
|
|
|
prepare:
|
|
cmds:
|
|
- task: build
|
|
status:
|
|
- '[ ! -f Dockerfile ]'
|
|
|
|
publish:
|
|
desc: Publish the Docker images (using `Docker*.test.yml` files)
|
|
hide:
|
|
sh: '[ ! -f Dockerfile ]'
|
|
summary: |
|
|
# Publish the Docker Images
|
|
|
|
This task will publish all of the corresponding Docker images as long as they
|
|
have a [container-structure-test](https://github.com/GoogleContainerTools/container-structure-test)
|
|
created.
|
|
|
|
For regular projects, having a `Docker.test.yml` container-structure-test is enough. However,
|
|
for projects with multiple build targets, there should be a test for each target. So, if there
|
|
are 2 build targets in the `Dockerfile` named `build1` and `build2` then there should be
|
|
a `Docker.build1.test.yml` and `Docker.build2.test.yml` container-structure-test.
|
|
cmds:
|
|
- |
|
|
if [ -d ./test/structure ]; then
|
|
TESTS="$(find ./test/structure -mindepth 1 -maxdepth 1 -type f -name "*.yml")"
|
|
if echo "$TESTS" | grep '.yml'; then
|
|
for TEST_FILE in $TESTS; do
|
|
TARGET="$(echo "$TEST_FILE" | sed 's/.*\/\([^\/]*\).yml$/\1/')"
|
|
task docker:publish:images -- "$TARGET"
|
|
done
|
|
else
|
|
.config/log error 'The `./test/structure` folder is present but there are no container-structure-tests in it. Add tests \
|
|
for each build target in the `Dockerfile` that you would like to generate an image for.'
|
|
exit 1
|
|
fi
|
|
else
|
|
.config/log info 'No `./test/structure` folder is present so assuming there is only one build target'
|
|
task docker:publish:images
|
|
fi
|
|
- task: pushrm
|
|
status:
|
|
- '[ ! -f Dockerfile ]'
|
|
|
|
publish:image:
|
|
vars:
|
|
SLIM_ENABLED:
|
|
sh: |
|
|
TYPE="$(jq -r '.blueprint.dockerSlimCommand | type' package.json)"
|
|
if [ "$TYPE" != 'object' ]; then
|
|
jq -r '.blueprint.dockerSlimCommand' package.json | sed 's/null/false/'
|
|
else
|
|
TARGET="{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}{{.TARGET}}{{end}}"
|
|
jq --arg target "$TARGET" -r '.blueprint.dockerSlimCommand[$target]' package.json | sed 's/null/false/'
|
|
fi
|
|
log:
|
|
error: Failed to tag / push `{{.DOCKER_IMAGE}}:{{.TARGET_TAG}}`
|
|
start: Tagging and pushing `{{.DOCKER_IMAGE}}:{{.TARGET_TAG}}`
|
|
success: Finished uploading `{{.DOCKER_IMAGE}}:{{.TARGET_TAG}}`
|
|
cmds:
|
|
- docker tag {{.DOCKER_IMAGE}}:{{.SOURCE_TAG}} {{.DOCKER_IMAGE}}:{{.TARGET_TAG}}
|
|
- docker push {{.DOCKER_IMAGE}}:{{.TARGET_TAG}}
|
|
status:
|
|
- '[[ "{{.SOURCE_TAG}}" == "slim"* ]]'
|
|
- '[[ "{{.SLIM_ENABLED}}" == "false" ]]'
|
|
|
|
publish:images:
|
|
vars:
|
|
MAJOR_VERSION:
|
|
sh: jq -r '.version' package.json | sed 's/\..*\..*$//'
|
|
MINOR_VERSION:
|
|
sh: jq -r '.version' package.json | sed 's/^[^\.]*\.//' | sed 's/\.[^\.]*$//'
|
|
TAG_POST: '{{if ne .DOCKER_BASE_TAG .CLI_ARGS}}-{{if (contains "codeclimate" .CLI_ARGS)}}codeclimate{{else}}{{.CLI_ARGS}}{{end}}{{end}}'
|
|
TARGET: '{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}{{.TARGET}}{{end}}'
|
|
VERSION:
|
|
sh: jq -r ".version" package.json
|
|
log:
|
|
error: An error occurred while publishing the Docker images
|
|
start: Publishing Docker images
|
|
success: Finished uploading all Docker images
|
|
cmds:
|
|
- task: publish:image
|
|
vars:
|
|
SOURCE_TAG: latest{{.TAG_POST}}
|
|
TARGET_TAG: 'v{{.VERSION}}{{.TAG_POST}}'
|
|
- task: publish:image
|
|
vars:
|
|
SOURCE_TAG: latest{{.TAG_POST}}
|
|
TARGET_TAG: 'v{{.MAJOR_VERSION}}{{.TAG_POST}}'
|
|
- task: publish:image
|
|
vars:
|
|
SOURCE_TAG: latest{{.TAG_POST}}
|
|
TARGET_TAG: v{{.MAJOR_VERSION}}.{{.MINOR_VERSION}}{{.TAG_POST}}
|
|
- task: publish:image
|
|
vars:
|
|
SOURCE_TAG: latest{{.TAG_POST}}
|
|
TARGET_TAG: latest{{.TAG_POST}}
|
|
- task: publish:image
|
|
vars:
|
|
SOURCE_TAG: slim{{.TAG_POST}}
|
|
TARGET_TAG: 'v{{.VERSION}}-slim{{.TAG_POST}}'
|
|
- task: publish:image
|
|
vars:
|
|
SOURCE_TAG: slim{{.TAG_POST}}
|
|
TARGET_TAG: 'v{{.MAJOR_VERSION}}-slim{{.TAG_POST}}'
|
|
- task: publish:image
|
|
vars:
|
|
SOURCE_TAG: slim{{.TAG_POST}}
|
|
TARGET_TAG: v{{.MAJOR_VERSION}}.{{.MINOR_VERSION}}-slim{{.TAG_POST}}
|
|
- task: publish:image
|
|
vars:
|
|
SOURCE_TAG: slim{{.TAG_POST}}
|
|
TARGET_TAG: slim{{.TAG_POST}}
|
|
|
|
pushrm:
|
|
deps:
|
|
- :install:github:docker-pushrm
|
|
- :install:software:docker
|
|
vars:
|
|
DOCKERHUB_DESCRIPTION:
|
|
sh: jq -r '.description' package.json
|
|
env:
|
|
DOCKER_PASS:
|
|
sh: echo "$DOCKERHUB_REGISTRY_PASSWORD"
|
|
DOCKER_USER: '{{.DOCKERHUB_USER}}'
|
|
cmds:
|
|
- cmd: docker pushrm {{.DOCKER_IMAGE}}
|
|
ignore_error: true
|
|
- cmd: docker pushrm --short '{{.DOCKERHUB_DESCRIPTION}}' {{.DOCKER_IMAGE}}
|
|
ignore_error: true
|
|
|
|
shell:
|
|
deps:
|
|
- :install:software:docker
|
|
- :install:software:jq
|
|
interactive: true
|
|
desc: Open the terminal of an existing Docker image
|
|
hide:
|
|
sh: '[ ! -f Dockerfile ]'
|
|
summary: |
|
|
# Shell into Docker Image
|
|
|
|
This task will start a shell session with one of the Docker images
|
|
that are currently present on machine. The task looks at the output
|
|
from `docker images` and filters the list based on the project's
|
|
expected DockerHub slug or a string, if you pass in CLI arguments.
|
|
|
|
**Displays a list of images that match the name in package.json:**
|
|
`task docker:shell`
|
|
|
|
**Displays a list of images that have the pattern abc in their name:**
|
|
`task docker:shell -- 'abc'`
|
|
vars:
|
|
IMAGE_OPTIONS:
|
|
sh: docker images | grep {{.DOCKER_IMAGE}} | sed 's/^\([^ ]*\).*$/\1/' | jq -Rsc 'split("\n")' | jq 'del(.[-1])'
|
|
prompt:
|
|
type: select
|
|
message: Which Docker image would you like to shell into?
|
|
options: '{{.IMAGE_OPTIONS}}'
|
|
answer:
|
|
cmds:
|
|
- docker run -v "${PWD}:/work" -w /work -it --entrypoint /bin/sh --rm {{.ANSWER}}
|
|
|
|
taskfile:deps:
|
|
vars:
|
|
DOCKER_TASKS_TAG:
|
|
sh: jq -r '.blueprint.dockerTasksTag' package.json
|
|
cmds:
|
|
- task: :common:util:task:tag:deps
|
|
vars:
|
|
TAG: '{{.DOCKER_TASKS_TAG}}'
|
|
status:
|
|
- '[ "{{.DOCKER_TASKS_TAG}}" == "null" ]'
|
|
|
|
test:
|
|
deps:
|
|
- :install:software:docker
|
|
desc: Perform all available tests on the Docker image
|
|
hide:
|
|
sh: '[ ! -f Dockerfile ]'
|
|
summary: |
|
|
# Test the Docker Images
|
|
|
|
This task will publish all of the corresponding Docker images as long as they
|
|
have a [container-structure-test](https://github.com/GoogleContainerTools/container-structure-test)
|
|
created.
|
|
|
|
For regular projects, having a `Docker.test.yml` container-structure-test is enough. However,
|
|
for projects with multiple build targets, there should be a test for each target. So, if there
|
|
are 2 build targets in the `Dockerfile` named `build1` and `build2` then there should be
|
|
a `Docker.build1.test.yml` and `Docker.build2.test.yml` container-structure-test.
|
|
|
|
## Comparing Slim Output to Latest Output
|
|
|
|
If the `dockerSlimCommand` is present in the `blueprint` section of `package.json`, the output from running
|
|
`npm run test:dockerslim` on every project/folder in the `test-output/` folder will be compared. The comparison
|
|
will ensure that the `slim` output matches the `latest` output. Each folder in the `test-output/` folder must
|
|
have a `package.json` file present with the `test:dockerslim` script defined under `scripts`.
|
|
|
|
If there is no `test-output/` folder, then this kind of test is skipped.
|
|
|
|
## `dockerSlimCommand` with Multiple Build Targets
|
|
|
|
If there are multiple build targets, then the `dockerSlimCommand` should be an object with keys equal to
|
|
the build targets and values equal to the appropriate DockerSlim command. If you are only using
|
|
`Docker.test.yml` then you can simply set `dockerSlimCommand` equal to the appropriate command. However,
|
|
if you have two targets named `build1` and `build2`, then your `dockerSlimCommand` should look something
|
|
like:
|
|
|
|
```json
|
|
{
|
|
"blueprint": {
|
|
"dockerSlimCommand": {
|
|
"build1": "...DockerSlim build command options here for build1",
|
|
"build2": "...DockerSlim build command options here for build2"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## CodeClimate CLI Testing
|
|
|
|
Any folder in the `test/` folder that starts with `codeclimate` gets scanned by CodeClimate CLI.
|
|
log:
|
|
error: Encountered error during Docker test sequence
|
|
start: Initiating Docker test sequence
|
|
success: Successfully completed Docker test sequence
|
|
cmds:
|
|
- task: :docker:test:container-structure-tests
|
|
- task: :docker:test:output
|
|
- task: :docker:test:codeclimate
|
|
- task: :docker:test:gitlab-runner
|
|
|
|
verify:
|
|
cmds:
|
|
- task: login
|
|
|
|
version:software:
|
|
cmds:
|
|
- |
|
|
if grep -q "CMD.\[\"--version\"\]" Dockerfile; then
|
|
VERSION=$(docker run --cap-drop=ALL -e PY_COLORS=0 --rm {{.DOCKER_IMAGE}}:latest | perl \
|
|
-pe 'if(($v)=/([0-9]+([.][0-9]+)+)/){print"$v";exit}$_=""')
|
|
if [[ $VERSION == *.*.* ]]; then
|
|
echo $VERSION
|
|
elif [[ $VERSION == *.* ]]; then
|
|
echo $VERSION.0
|
|
fi
|
|
fi
|