-
Notifications
You must be signed in to change notification settings - Fork 2
/
Makefile
197 lines (150 loc) · 6.53 KB
/
Makefile
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
SHELL=bash
.SHELLFLAGS=-ec -o pipefail
current_makefile:=$(lastword $(MAKEFILE_LIST))
current_makefile_dir:=$(dir $(abspath $(current_makefile)))
.PHONY: all
all: ## do everything (default target)
########################################################################
# boiler plate
########################################################################
SHELL=bash
.SHELLFLAGS=-ec -o pipefail
current_makefile:=$(lastword $(MAKEFILE_LIST))
current_makefile_dirname:=$(dir $(current_makefile))
current_makefile_dirname_abspath:=$(dir $(abspath $(current_makefile)))
current_makefile_dirname_realpath:=$(dir $(realpath $(current_makefile)))
ifneq ($(filter all vars,$(VERBOSE)),)
dump_var=$(info var $(1)=$($(1)))
dump_vars=$(foreach var,$(1),$(call dump_var,$(var)))
else
dump_var=
dump_vars=
endif
ifneq ($(filter all targets,$(VERBOSE)),)
__ORIGINAL_SHELL:=$(SHELL)
SHELL=$(warning Building $@$(if $<, (from $<))$(if $?, ($? newer)))$(TIME) $(__ORIGINAL_SHELL)
endif
giti_commit_hash=$(shell git log -1 --format="%H")
oci_tag_suffixes_git = \
gitc-$(giti_commit_hash) \
define __newline
endef
$(call dump_vars,current_makefile current_makefile_dirname \
current_makefile_dirname_abspath current_makefile_dirname_realpath)
########################################################################
# variables
########################################################################
oci_output_dir=var/oci-images
########################################################################
# targets
########################################################################
images_dir=images
IMAGE_NAMES?=$(notdir $(wildcard $(images_dir)/*))
$(call dump_vars,IMAGE_NAMES)
docker=docker
docker_compose=docker compose
# docker_image_build_cmd=$(docker) image build
docker_image_build_cmd=$(docker) buildx build --progress plain --load
docker_image_build_args?=
docker_image_build=$(docker_image_build_cmd) $(docker_image_build_args)
hadolint=$(docker_compose) run --rm -T hadolint
oci_local_ref_prefix=ocreg.invalid/coopnorge/engineering/image/
oci_remote_ref_prefixes=\
all: build
build: ## build artifacts
py_source=$(shell find images/ -type f -name '*.py')
validate-python: ## Validate Python code
poetry check
poetry run isort --check-only --diff $(py_source)
poetry run black --config ./pyproject.toml --check --diff $(py_source)
poetry run pflake8 $(py_source)
$(foreach file, $(py_source), poetry run mypy --show-error-codes --show-error-context --pretty $(file) &&) true
validate-fix-python: ## Fix auto-fixable validation errors in Python
poetry run python -m isort images
poetry run python -m black --config ./pyproject.toml images
validate-dockerfile-%: ## Validate a specific dockerfile
$(hadolint) < images/$(*)/context/Dockerfile
validate_dockerfile_targets=$(foreach image_name,$(IMAGE_NAMES),validate-dockerfile-$(image_name))
.PHONY: validate-static
validate-static: $(validate_dockerfile_targets) validate-python ## Run static validation
.PHONY: validate
validate: validate-static test ## Validate everything
.PHONY: build-image-%
build-image-%: ## Build a specific image
$(docker_image_build) \
--tag $(oci_local_ref_prefix)$(*):built \
images/$(*)/context/
build_image_targets=$(foreach build_image_name,$(IMAGE_NAMES),build-image-$(build_image_name))
build-images: ## build all images
build: build-images
build-images: $(build_image_targets)
.PHONY: test-image-%
test-image-%: ## Test a specific image
IMAGE_UNDER_TEST=$(oci_local_ref_prefix)$(*):built \
images/$(*)/tests/run
test_image_targets=$(foreach image_name,$(IMAGE_NAMES),test-image-$(image_name))
.PHONY: test
test: $(test_image_targets) ## Test all images
.PHONY: tag-image-%
tag-image-%: build-image-%
$(foreach oci_remote_ref_prefix,$(oci_remote_ref_prefixes),\
$(docker) tag $(oci_local_ref_prefix)$(*):built $(oci_remote_ref_prefix)$(*):$(oci_tag_suffixes_git) $(__newline) \
$(docker) tag $(oci_local_ref_prefix)$(*):built $(oci_remote_ref_prefix)$(*):latest $(__newline))
tag_image_targets=$(foreach image_name,$(IMAGE_NAMES),tag-image-$(image_name))
.PHONY: tag-images
tag-images: $(tag_image_targets) ## Tag all images
.PHONY: push-image-%
push-image-%: tag-image-% ## Push a specific image
$(foreach oci_remote_ref_prefix,$(oci_remote_ref_prefixes),\
$(docker) push $(oci_remote_ref_prefix)$(*):$(oci_tag_suffixes_git) $(__newline) \
$(docker) push $(oci_remote_ref_prefix)$(*):latest $(__newline))
push_image_targets=$(foreach image_name,$(IMAGE_NAMES),push-image-$(image_name))
push-images: $(push_image_targets) ## Push all images
.PRECIOUS: $(oci_output_dir)/%.oci.tar
$(oci_output_dir)/%.oci.tar: image-% | $(oci_output_dir)/
$(docker) image save -o $(@) $(oci_local_ref_prefix)$(*):built
.PHONY: save-image-%
save-image-%: $(oci_output_dir)/%.oci.tar ## save a specific image
echo "$(<) -> $(@)"
save_image_targets=$(foreach image_name,$(IMAGE_NAMES),save-image-$(image_name))
.PHONY: save-images
save-images: $(save_image_targets)
load-opt-image-%: ## Loads a specific image if it exists
if [ -e $(oci_output_dir)/$(*).oci.tar ]; \
then \
$(docker) image load -i $(oci_output_dir)/$(*).oci.tar; \
else \
echo "NOTE: not loading $(oci_output_dir)/$(*).oci.tar as it does not exist"; \
fi;
load_opt_image_targets=$(foreach image_name,$(IMAGE_NAMES),load-opt-image-$(image_name))
.PHONY: load-opt-images
load-opt-images: $(load_opt_image_targets) ## Loads all images
load-any-images: | $(oci_output_dir)/ ## Loads any images that are found
find $(oci_output_dir)/ -name '*.oci.tar' -print0 \
| xargs --no-run-if-empty -0 -n1 -t $(docker) image load -i
########################################################################
# docker-lock
########################################################################
docker_lock=$(docker_compose) run --rm -T docker-lock
#docker_lock=docker-lock
.PHONY: docker-lock
docker-lock: ## Generate and rewrite digests of docker images
$(docker_lock) lock generate
$(docker_lock) lock rewrite
.PHONY: validate-images-digests
validate-images-digests: ## Validate images digests
$(docker_lock) lock verify
########################################################################
# utility
########################################################################
.PHONY: help
help: ## show this message
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
## clean directories
.PHONY: clean-%/
clean-%/:
@{ test -d $(*) && { set -x; rm -vr $(*); set +x; } } || echo "directory $(*) does not exist ... nothing to clean"
## create directories
.PRECIOUS: %/
%/:
mkdir -vp $(@)