-
Notifications
You must be signed in to change notification settings - Fork 0
231 lines (190 loc) · 8.17 KB
/
docker.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
############################################
## Docker Build & Docker Push (Dockerhub) ##
## Reusable Workflow ##
############################################
# Build Docker image, authenticate with Dockerhub,
# and push image to Dockerhub public Registry.
## AUTONOMOUS DOCKER JOB ##
# Features:
# Configurable Behaviour, using Policies (see input.acceptance_policy):
# 0. Never run Docker build and publish to Dockerhub
# aka: 'NO Docker', Docker Shutdown, 'No Admitance'
# aka: guarantee that nothing is published
# 1. Always build and publish to Dockerhub
# aka: Force Publish, Always Docker, 'Admit All'
# aka: 'Free Admitance', 'No Entry Barrier', 'Free Entrance'
# 2. Run Docker build and publish to Dockerhub only if Tests passed (and ran!)
# aka: Continous Integration / Continuous Deployment (CI/C Dpl)
# aka: guranteed quality, everything published is tested
# aka: 'required succesful evaluation', 'accept only a Pass'
# 3. Run Docker build and publish to Dockerhub, if Tests ran and passed, but also if Tests were skipped
# aka: Continous Integration / Continuous Delivery (CI/C Dlv)
# aka: CI/CD with Bypass Option
# aka: 'accepted_when_Test_OFF', 'accept a Pass or a Skip'
# aka: 'admit when test is off'
# Build from Dockerfile in repo root directory
# Authenticates to Dockerhub, using credentials stored in Github Secrets
# Logout from Dockerhub, regardless of whether the push succeeded or failed
# Steps:
# 1. Docker Build
# 2. Login to Dockerhub
# 3. Push to Dockerhub, noting success
# 4. Logout from Dockerhub
# 5. Finish Job, if Push succeded, else Fail Job
### Workflow INPUTS ###
# 1. Docker Image Slug
# 2. Docker Policy (number)
# 3. Docker Username
# 4. Docker Password (Secret)
on:
# Trigger when called from another workflow
# Aka parent/caller workflow calls the child/"called" workflow
workflow_call:
inputs:
DOCKER_USER:
required: true
type: string
image_slug:
required: true
type: string
tests_pass:
required: false
type: boolean
tests_run:
required: false
type: boolean
# Defaults to CI/CD if unknown policy or not given
acceptance_policy:
required: false
type: string
target_stage:
required: false
type: string
image_tag:
required: false
type: string
secrets:
DOCKER_PASSWORD:
required: true
# Map the workflow outputs to job outputs
outputs:
IMAGE_REF:
description: "Docker Image reference"
value: ${{ jobs.docker_build.outputs.IMAGE_REF }}
jobs:
## AUTONOMOUS DOCKER BUILD and PUBLISH ON DOCKERHUB ##
docker_build:
outputs:
IMAGE_REF: ${{ steps.build_docker_image.outputs.IMAGE_REF }}
## Policy Logic ##
# 2 bit state machine
# 0 0 = 0: Never build, aka No Admitance, guarantee NO Dockerhub publish
# 0 1 = 1: Always build and publish, aka Admit All, Force Docker
# 1 0 = 2: CI/CD pure mode, aka Admit only if Pass, Require Pass, guarantee quality
# 1 1 = 3: CI/CD with Bypass Opt, aka Admit Tested and when Test is OFF, Admit when Test OFF
if: always() && inputs.acceptance_policy != 0 && ( inputs.acceptance_policy == 1 || (
inputs.tests_pass && inputs.tests_run ) || (
inputs.acceptance_policy == 3 && inputs.tests_pass == false && inputs.tests_run == false )
)
runs-on: ubuntu-latest
env:
IMAGE_SLUG: ${{ inputs.image_slug }}
TARGET_STAGE: ${{ inputs.target_stage }}
DOCKER_USER: ${{ inputs.DOCKER_USER }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
steps:
# DEBUG
- run: echo ${{ inputs.acceptance_policy }}
- name: "REQ to RUN: Policy is NOT 00 AND"
run: echo ${{ inputs.acceptance_policy != 0 }}
- name: "ONE OF: Policy IS 01"
run: echo ${{ inputs.acceptance_policy == 1 }}
- name: "Check needs SUCCESS 1"
run: echo ${{ contains(needs.*.result, 'success') }}
- name: "Check needs SUCCESS 2"
run: echo ${{ needs.*.result == 'success' }}
- run: echo ${{ !contains(needs.*.result, 'failure') }}
- run: echo ${{ !contains(needs.*.result, 'cancelled') }}
- name: "ONE OF: needs SUCCESS and NOT Skipped and NOT Cancelled"
run: echo ${{ contains(needs.*.result, 'success') && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') }}
- run: echo ${{ inputs.acceptance_policy == 3 }}
- run: echo ${{ !contains(needs.*.result, 'failure') }}
- run: echo ${{ contains(needs.*.result, 'skipped') }}
- run: echo ${{ contains(needs.*.result, 'cancelled') }}
- name: "ONE OF: Pol is 3 and NOT Failure and (SKIPPED OR Cancelled)"
run: echo ${{ inputs.acceptance_policy == 3 && !contains(needs.*.result, 'failure') && ( contains(needs.*.result, 'skipped') || contains(needs.*.result, 'cancelled') ) }}
##
- run: 'echo "POLICY: ${{ inputs.acceptance_policy }}"'
- run: 'echo "IMAGE (repo/name): ${{ inputs.image_slug }}"'
- run: 'echo "TARGET_STAGE: ${{ inputs.target_stage }}"'
- run: |
echo "=== ENV VARS ==="
echo "Docker Username: ${DOCKER_USER}"
echo "Image Slug ${IMAGE_SLUG}"
echo "Target Stage: ${TARGET_STAGE}"
echo === INPUTS ===
echo ${{ inputs.DOCKER_USER }}
echo ${{ inputs.image_slug }}
echo ${{ inputs.acceptance_policy }}
echo ${{ inputs.target_stage }}
echo ${{ inputs.image_tag }}
echo === SECRETS ===
echo ${DOCKER_PASSWORD}
- uses: actions/checkout@v3
- run: echo ${{ github.ref }}
- run: echo ${{ github.ref_name }}
- run: echo "IMAGE_TAG=${{ inputs.image_tag || github.ref_name }}" >> $GITHUB_ENV
- name: Build Docker Image from Dockerfile
id: build_docker_image
run: |
# tag image with input tag if given
IMAGE_TAG="${{ inputs.image_tag }}"
echo "[DEBUG] IMAGE_TAG: $IMAGE_TAG"
# else use the git ref, which normally a branch or tag name
# assuming workflow is enabled for branches and v* tags
[ -z "$IMAGE_TAG" ] && IMAGE_TAG="${GITHUB_REF_NAME}"
IMAGE_REF="${DOCKER_USER}/${IMAGE_SLUG}:${IMAGE_TAG}"
echo "[DEBUG] IMAGE_REF: $IMAGE_REF"
echo " == Image Tag from Git Ref: $IMAGE_TAG == "
echo " == Image Slug: $IMAGE_SLUG == "
echo " == Image Ref: $IMAGE_REF == "
# Set TARGET_FLAG to --target $TARGET_STAGE or an empty string
TARGET_FLAG="--target $TARGET_STAGE"
# Remove the --target flag if DOCKER_TARGET is empty
[ -z "$TARGET_STAGE" ] && TARGET_FLAG=""
echo "[DEBUG] TARGET_FLAG: $TARGET_FLAG"
BUILD_CMD="docker build ${TARGET_FLAG} -t ${IMAGE_REF} ."
echo "[DEBUG] BUILD_CMD: $BUILD_CMD"
sh -c "$BUILD_CMD"
# Build the Docker image with or without the target flag
# docker build "$TARGET_FLAG" -t "${IMAGE_REF}" .
echo " -- DOCKER BUILD DONE --"
echo " -- IMAGE: ${IMAGE_REF}"
echo "IMAGE_REF=${IMAGE_REF}" >> $GITHUB_ENV
echo "IMAGE_REF=${IMAGE_REF}" >> $GITHUB_OUTPUT
- name: Login to Dockerhub, public Image Registry
env:
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
run: echo "${DOCKER_PASSWORD}" | docker login --username "${DOCKER_USER}" --password-stdin
- name: Publish to DockerHub; Push Docker Image
run: |
push_success=1
docker push "${IMAGE_REF}" || push_success=0
if [ $push_success -eq 1 ]; then
echo "Docker Image "${IMAGE_REF}" pushed to DockerHub!"
else
echo "[ERROR] Docker push failed!"
fi
echo "push_success=$push_success" >> $GITHUB_ENV
- name: Logout from Dockerhub
run: docker logout
- name: Exit Job, with status code 0 if push was successful
run: |
if [ $push_success -eq 1 ]; then
job_status=0
else
echo "[ERROR] Docker push failed!"
job_status=1
fi
echo "Exiting with status code: $job_status"
exit $job_status