From f3b6cb144152e448c86be96c9d7bc77187a350a1 Mon Sep 17 00:00:00 2001 From: Jordan Cleal Date: Sat, 2 Apr 2022 10:01:46 +1100 Subject: [PATCH 01/19] ignore some cf files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 408d7db..e451d18 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ super-linter.log # ignore folders generated via CI/CD. /depot /bin/[0-9][0-9]-*.sh +/cf/[0-9][0-9]-*.yml /.github/templates/[0-9][0-9]-* From 89994a46492bc21e583baf48b61c6656e5ce0050 Mon Sep 17 00:00:00 2001 From: Jordan Cleal Date: Sat, 2 Apr 2022 21:27:30 +1100 Subject: [PATCH 02/19] remove markdown from editorconfig --- .editorconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/.editorconfig b/.editorconfig index 9841ae8..6857f76 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,8 +14,5 @@ indent_size = 2 indent_style = tab indent_size = 4 -[*.md] -indent_size = 4 - [Dockerfile] indent_size = 4 From a6425e516b4a66163381d0c57673747265055a06 Mon Sep 17 00:00:00 2001 From: Jordan Cleal Date: Fri, 8 Apr 2022 11:13:55 +1000 Subject: [PATCH 03/19] Create LICENSE --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..412a49f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Jordan Cleal + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From fa6a64d40e2f7a51621aed410c95cddcabbcabc8 Mon Sep 17 00:00:00 2001 From: Jordan Cleal Date: Sat, 5 Aug 2023 22:41:06 +1000 Subject: [PATCH 04/19] clean up workflows --- .github/workflows/cicd.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index 2075dc2..e7a3873 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -1,5 +1,6 @@ --- name: CI/CD + on: push: workflow_dispatch: From 3ed59145b51dcce0a02027c982d2cbd4b2c84237 Mon Sep 17 00:00:00 2001 From: Jordan Cleal Date: Sat, 5 Aug 2023 22:45:57 +1000 Subject: [PATCH 05/19] revamp this repo with new standards --- .editorconfig | 13 ++++--------- .github/workflows/README.yml | 22 ++++++++++++---------- .github/workflows/cicd.yml | 32 ++++++++++++++++++++++---------- .gitignore | 24 +++++++++++++----------- LICENSE | 2 +- 5 files changed, 52 insertions(+), 41 deletions(-) diff --git a/.editorconfig b/.editorconfig index 6857f76..226e4f0 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,18 +1,13 @@ root = true [*] -end_of_line = lf +indent_style = space +indent_size = 2 charset = utf-8 +end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true -spaces_around_operators = true -spaces_around_brackets = false -indent_style = space -indent_size = 2 -[{Makefile,go.mod,go.sum,*.go,.gitmodules}] +[Makefile*] indent_style = tab indent_size = 4 - -[Dockerfile] -indent_size = 4 diff --git a/.github/workflows/README.yml b/.github/workflows/README.yml index c90378f..255063a 100644 --- a/.github/workflows/README.yml +++ b/.github/workflows/README.yml @@ -3,22 +3,24 @@ name: README.md on: push: paths: - - '.github/templates/*' - '.github/workflows/*' - - 'img/*' + - 'templates/*' + - 'docs/*' workflow_dispatch: + repository_dispatch: + types: [update-readme] + +permissions: + id-token: write + contents: write jobs: generate-readme: - uses: jmpa-io/depot/.github/workflows/README.yml@main - secrets: - github-token: ${{ secrets.ADMIN_GITHUB_TOKEN }} - slack-webhook: ${{ secrets.SLACK_GITHUB_WEBHOOK_URL }} + uses: jmpa-io/roots/.github/workflows/README.yml@main + secrets: inherit post-to-slack: needs: [generate-readme] if: always() - uses: jmpa-io/depot/.github/workflows/post-to-slack.yml@main - secrets: - github-token: ${{ secrets.ADMIN_GITHUB_TOKEN }} - slack-webhook: ${{ secrets.SLACK_GITHUB_WEBHOOK_URL }} + uses: jmpa-io/roots/.github/workflows/post-to-slack.yml@main + secrets: inherit diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index e7a3873..0f72f93 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -1,22 +1,34 @@ --- name: CI/CD - on: push: + paths: + - '.github/workflows/cicd.yml' + - 'bin/*' + - 'cf/**' + - 'cmd/**' + - 'templates/**' + - '**Dockerfile' + - 'Makefile*' workflow_dispatch: repository_dispatch: - types: [trigger] + types: [update-cicd] + +permissions: + id-token: write + contents: read jobs: lint: - uses: jmpa-io/depot/.github/workflows/lint.yml@main - secrets: - github-token: ${{ secrets.ADMIN_GITHUB_TOKEN }} + uses: jmpa-io/roots/.github/workflows/lint.yml@main + secrets: inherit + + test: + uses: jmpa-io/roots/.github/workflows/test.yml@main + secrets: inherit post-to-slack: - needs: [lint] + needs: [lint, test] if: always() - uses: jmpa-io/depot/.github/workflows/post-to-slack.yml@main - secrets: - github-token: ${{ secrets.ADMIN_GITHUB_TOKEN }} - slack-webhook: ${{ secrets.SLACK_GITHUB_WEBHOOK_URL }} + uses: jmpa-io/roots/.github/workflows/post-to-slack.yml@main + secrets: inherit diff --git a/.gitignore b/.gitignore index e451d18..4f32044 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,17 @@ # ignore general files. -.DS_store +.DS_Store +.vscode/ -# ignore test files. -out -test.sh +# ignore generated files. +/out +package.yml +coverage.* +dist/ +*.zip +*.pem -# ignore log files. -super-linter.log +# ignore test files. +/test.sh -# ignore folders generated via CI/CD. -/depot -/bin/[0-9][0-9]-*.sh -/cf/[0-9][0-9]-*.yml -/.github/templates/[0-9][0-9]-* +# ignore compiled binaries in root. +/main diff --git a/LICENSE b/LICENSE index 412a49f..79f4e21 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Jordan Cleal +Copyright (c) 2023 Jordan Cleal Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 874480495e7b322f6602734c6de48c0e0c6a82fb Mon Sep 17 00:00:00 2001 From: Jordan Cleal Date: Sat, 5 Aug 2023 22:50:15 +1000 Subject: [PATCH 06/19] add Makefile --- Makefile | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9d21e20 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +PROJECT = root-template + +---: ## --- + +# include common targets. +include Makefile.common.mk From a83b41eb4132173dbeb298fa742473a9505bd749 Mon Sep 17 00:00:00 2001 From: jcleal Date: Sat, 5 Aug 2023 12:56:39 +0000 Subject: [PATCH 07/19] [skip ci] Updated README.md --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f891c47..0c4af91 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,15 @@ -[![root-template](https://github.com/jmpa-io/root-template/actions/workflows/cicd.yml/badge.svg)](https://github.com/jmpa-io/root-template/actions/workflows/cicd.yml) -[![root-template](https://github.com/jmpa-io/root-template/actions/workflows/README.yml/badge.svg)](https://github.com/jmpa-io/root-template/actions/workflows/README.yml) +[![README.yml](https://github.com/jmpa-io/root-template/actions/workflows/README.yml/badge.svg)](https://github.com/jmpa-io/root-template/actions/workflows/README.yml) +[![cicd.yml](https://github.com/jmpa-io/root-template/actions/workflows/cicd.yml/badge.svg)](https://github.com/jmpa-io/root-template/actions/workflows/cicd.yml) # `root-template` ```diff -+ 🌱 The root template used by all other repositories in this org. ++ 🧱 A template used to store any generic files used by all other repositories in ++ this org. Used in conjunction with https://github.com/jmpa-io/depot. ``` -## How do I use this template? +## 🧠 How do I use this template? 1. Using a terminal, download the child repository locally. @@ -17,5 +18,5 @@ git remote add template https://github.com/jmpa-io/root-template.git git fetch template git merge template/main --allow-unrelated-histories -# then fix any merge conflicts as required & 'git push' when ready. +# then fix any merge conflicts as required %HOW_TO_USE_TEMPLATE% 'git push' when ready. ``` From 87e8ee544f2df2a315a46b6748d09bd87b91c160 Mon Sep 17 00:00:00 2001 From: Jordan Cleal Date: Sun, 6 Aug 2023 17:53:06 +1000 Subject: [PATCH 08/19] add actions read to all workflows that need it --- .github/workflows/README.yml | 1 + .github/workflows/cicd.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/README.yml b/.github/workflows/README.yml index 255063a..9e9676a 100644 --- a/.github/workflows/README.yml +++ b/.github/workflows/README.yml @@ -13,6 +13,7 @@ on: permissions: id-token: write contents: write + actions: read jobs: generate-readme: diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index 0f72f93..3d90371 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -17,6 +17,7 @@ on: permissions: id-token: write contents: read + actions: read jobs: lint: From 26bc822ff4d00fed86028341e32307702dc8476d Mon Sep 17 00:00:00 2001 From: jcleal Date: Sun, 6 Aug 2023 07:54:22 +0000 Subject: [PATCH 09/19] [skip ci] Updated README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0c4af91..c2ee7bd 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ ```diff + 🧱 A template used to store any generic files used by all other repositories in -+ this org. Used in conjunction with https://github.com/jmpa-io/depot. ++ this org. Used in conjunction with https://github.com/jmpa-io/roots. ``` ## 🧠 How do I use this template? From 5a8fa6d9df2954a2d41696dd112f921d016e3661 Mon Sep 17 00:00:00 2001 From: jcleal Date: Tue, 16 Apr 2024 10:12:57 +1000 Subject: [PATCH 10/19] add Makefile.common.mk --- Makefile.common.mk | 399 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 399 insertions(+) create mode 100644 Makefile.common.mk diff --git a/Makefile.common.mk b/Makefile.common.mk new file mode 100644 index 0000000..e7ce90e --- /dev/null +++ b/Makefile.common.mk @@ -0,0 +1,399 @@ +# +# This Makefile is generic across all repositories: +# https://github.com/jmpa-io/root-template/blob/main/Makefile.common.mk +# +# See the bottom for additional notes. +# + +# Check project variables are given. +ifndef PROJECT +$(error PROJECT not defined, missing from Makefile?) +endif + +# Variables. +SHELL = /bin/sh # The shell to use for executing commands. +ENVIRONMENT ?= dev # The environment to deploy to. +COMMIT = $(shell git describe --tags --always) # The git commit hash. +REPO = $(shell basename $(shell git rev-parse --show-toplevel)) # The name of the repository. +COMMA := , # Used for if conditions in Make where a comma is needed. +OS := $(shell uname | tr '[:upper:]' '[:lower:]') # The operating system the Makefile is being executed on. +BUILDING_OS ?= $(OS) # The operating system used when building binaries. +SUPPORTED_OPERATING_SYSTEMS = linux,darwin # A list of operating systems that can be used when building binaries. + +# Setup OS specific variables. +ifeq ($(OS),linux) + SED_FLAGS = -i + FILE_SIZE = $(shell stat -c '%s' $<) +else ifeq ($(OS),darwin) + SED_FLAGS = -i '' + FILE_SIZE = $(shell stat -f '%z' $<) +endif + +# Files + Directories. +SH_FILES := $(shell find . $(IGNORE_SUBMODULES) -name "*.sh" -type f 2>/dev/null) +GO_FILES := $(shell find . $(IGNORE_SUBMODULES) -name "*.go" -type f 2>/dev/null) +CF_FILES := $(shell find ./cf $(IGNORE_SUBMODULES) -name 'template.yml' -type f 2>/dev/null) +SAM_FILES := $(shell find ./cf $(IGNORE_SUBMODULES) -name 'template.yaml' -type f 2>/dev/null) +CF_DIRS := $(shell find ./cf $(IGNORE_SUBMODULES) -mindepth 1 -maxdepth 1 -type d 2>/dev/null) +CMD_DIRS := $(shell find ./cmd $(IGNORE_SUBMODULES) -mindepth 1 -maxdepth 1 -type d 2>/dev/null) +IMAGES := $(patsubst .,$(PROJECT),$(patsubst ./%,%,$(shell find . -name 'Dockerfile' -type f -exec dirname {} \; 2>/dev/null))) + +# Submodules. +SUBMODULES := $(shell git config --file $(shell while [[ ! -d .git ]]; do cd ..; done; pwd)/.gitmodules --get-regexp path | awk '{ print $$2 }') +IGNORE_SUBMODULES = $(foreach module,$(SUBMODULES),-not \( -path "./$(module)" -o -path "./$(module)/*" \)) + +# Binaries. +CMD_DIRS = $(shell find cmd/* -name main.go -maxdepth 1 -type f -exec dirname {} \; 2>/dev/null | awk -F/ '{$$1=""; sub(/^ /, ""); print $$0}') +CMD_SOURCE = $(addprefix cmd/,$(CMD_DIRS)) +BINARIES_TARGETS = $(addprefix binary-,$(CMD_DIRS)) +BINARIES_OUTPUT_DIRECTORIES = $(addprefix dist/,$(CMD_DIRS)) + +# AWS. +AWS_REGION ?= ap-southeast-2 +STACK_NAME = $(PROJECT)-$* +AWS_ACCOUNT_ID ?= $(shell aws sts get-caller-identity --query 'Account' --output text) +ECR = $$(AWS_ACCOUNT_ID).dkr.ecr.$(AWS_REGION).amazonaws.com +BUCKET ?= jmpa-io-artifacts + +# Funcs. +get_last_element = $(lastword $(subst /, ,$1)) # Splits a string by '/' and retrieves the last element in the given array. + +# Check deps. +ifndef CI +EXECUTABLES ?= awk aws cfn-lint column find go golangci-lint grep hadolint sam zip +MISSING := $(strip $(foreach bin,$(EXECUTABLES),$(if $(shell command -v $(bin) 2>/dev/null),,$(bin)))) +$(if $(MISSING),$(error Please install: $(MISSING))) +endif + +# The default command executed when running `make`. +.DEFAULT_GOAL:= help + +# ┬ ┬ ┌┐┌┌┬┐ +# │ │ │││ │ +# ┴─┘┴ ┘└┘ ┴ + +.PHONY: lint +lint: lint-sh lint-go lint-cf lint-sam lint-docker ## ** Lints everything. + +.PHONY: lint-sh +lint-sh: ## Lints shell files. + @test -z "$(CI)" || echo "##[group]Linting sh." +ifeq ($(SH_FILES),) + @echo "No *.sh files to lint." +else + find . -type f -name "*.sh" -exec shellcheck '{}' \+ || true +endif + @test -z "$(CI)" || echo "##[endgroup]" + +.PHONY: lint-go +lint-go: ## Lints Go files. + @test -z "$(CI)" || echo "##[group]Linting Go." +ifeq ($(GO_FILES),) + @echo "No *.go files to lint." +else + golangci-lint run -v --allow-parallel-runners ./... +endif + @test -z "$(CI)" || echo "##[endgroup]" + +.PHONY: lint-cf +lint-cf: ## Lints CF templates. + @test -z "$(CI)" || echo "##[group]Linting Cloudformation." +ifeq ($(CF_FILES),) + @echo "No ./cf/*/template.yml files to lint." +else + find ./cf -type f -name 'template.yml' -exec sh -c 'cfn-lint -r $(AWS_REGION) -t "{}" && aws cloudformation validate-template --template-body file://{}' \; +endif + @test -z "$(CI)" || echo "##[endgroup]" + +.PHONY: lint-sam +lint-sam: ## Lints SAM templates. + @test -z "$(CI)" || echo "##[group]Linting sam." +ifeq ($(SAM_FILES),) + @echo "No ./cf/*/template.yaml files to lint." +else + find ./cf -type f -name 'template.yaml' -exec sam validate --region $(AWS_REGION)-t '{}' \; || true +endif + @test -z "$(CI)" || echo "##[endgroup]" + +.PHONY: lint-docker +lint-docker: ## Lints Dockerfiles. + @test -z "$(CI)" || echo "##[group]Linting Docker." +ifeq ($(DOCKER_FILES),) + @echo "No Dockerfiles to lint." +else + find . -type f -name 'Dockerfile' -exec hadolint '{}' \; || true +endif + @test -z "$(CI)" || echo "##[endgroup]" + +# ┌┬┐┌─┐┌─┐┌┬┐ +# │ ├┤ └─┐ │ +# ┴ └─┘└─┘ ┴ + +.PHONY: test +test: test-go ## ** Tests everything. + +.PHONY: test-go +test-go: dist/coverage.txt ## Runs Go tests. +dist/coverage.txt: dist + @test -z "$(CI)" || echo "##[group]Unit tests." +ifeq ($(GO_FILES),) + @echo "No *.go files to test." +else + @go version + CGO_ENABLED=1 go test -short -coverprofile=$@ \ + -covermode=atomic -race -vet=off ./... +endif + @test -z "$(CI)" || echo "##[endgroup]" + +.PHONY: code-coverage +code-coverage: dist/coverage.txt ## Generates a Go code coverage report, broken-down by function, to stdout. + @if [[ -f $< ]]; then \ + test -z "$(CI)" || echo "##[group]Code coverage."; \ + go tool cover -func=$<; \ + test -z "$(CI)" || echo "##[endgroup]"; \ + fi + +.PHONY: code-coverage-html +code-coverage-html: dist/coverage.txt ## Generates a Go code HTML coverage report, rendered in the default browser. + @if [[ -f $< ]]; then \ + go tool cover -html=$<; \ + fi + +# ┌┐ ┬┌┐┌┌─┐┬─┐┬┌─┐┌─┐ +# ├┴┐││││├─┤├┬┘│├┤ └─┐ +# └─┘┴┘└┘┴ ┴┴└─┴└─┘└─┘ + +.PHONY: binaries binaries-all +binaries: $(BINARIES_TARGETS) ## ** Builds ALL binaries for the $(BUILDING_OS) environment. +binaries-all: ## ** Builds ALL binaries for ALL supported operating systems. + @for os in $(shell echo $(SUPPORTED_OPERATING_SYSTEMS) | tr ',' ' '); do \ + $(MAKE) --no-print-directory BUILDING_OS=$$os binaries; \ + done + +# Creates the root output directory. +dist: + @mkdir -p dist + +# Creates the output directory, for a given service. +.SECONDARY: $(BINARIES_OUTPUT_DIRECTORIES) +dist/%: dist + @mkdir -p dist/$* + +# Builds a binary, for the given service, for the Linux environment. +define build_binary_linux + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \ + go build --trimpath \ + -tags lambda.norpc \ + -ldflags "-w -s -X version.Version=$(COMMIT)" \ + -o dist/$*/$*-linux-amd64 ./cmd/$* +endef + +# Builds a binary, for the given service, for the Darwin environment. +define build_binary_darwin + CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 \ + go build --trimpath \ + -ldflags "-w -s -X version.Version=$(COMMIT)" \ + -o dist/$*/$*-darwin-arm64 ./cmd/$* +endef + +# A wrapper for building a binary, for the given service, for the $(BUILDING_OS) environment. +define build_binary + @echo "##[group]Building $* binary for $1." + @go version + $(call build_binary_$1) + @test -z "$(CI)" || echo "##[endgroup]" +endef + +## Builds a binary, for the given service, for the $(BUILDING_OS) environment. +binary-%: cmd/%/main.go dist/% + $(call build_binary,$(BUILDING_OS)) + +# ┬ ┌─┐┌┬┐┌┐ ┌┬┐┌─┐ +# │ ├─┤│││├┴┐ ││├─┤ +# ┴─┘┴ ┴┴ ┴└─┘─┴┘┴ ┴ + +# Moves the bootstrap, for the given service, into the dist directory. +bootstrap-%: dist/% cmd/%/bootstrap + @cp cmd/$*/bootstrap dist/$*/ + +# Invokes the given service locally, if able. +invoke-%: cmd/%/local.sh binary-% bootstrap-% + @$< + +# ┌┬┐┌─┐┌─┐┬┌─┌─┐┬─┐ +# │││ ││ ├┴┐├┤ ├┬┘ +# ─┴┘└─┘└─┘┴ ┴└─┘┴└─ + +.PHONY: images +images: $(foreach image,$(IMAGES),image-$(image)) ## ** Builds ALL docker images for each service. + +define build_image +.PHONY: image-$1 +## Builds the docker image for the given service. +image-$1: dist/$1-linux $(subst $(PROJECT),.,$1)/Dockerfile + @test -z "$(CI)" || echo "##[group]Building $(strip $(call get_last_element,$(subst .,,$1))) image." + docker build -t $(if $(filter $1,$(PROJECT)),$1,$(PROJECT)/$(strip $(call get_last_element,$1))):$(COMMIT) -t $(if $(filter $1,$(PROJECT)),$1,$(PROJECT)/$(strip $(call get_last_element,$1))):latest -f $(if $(filter $1,$(PROJECT)),./,$1/Dockerfile) . + @test -z "$(CI)" || echo "##[endgroup]" +endef +$(foreach image,$(IMAGES),$(eval $(call build_image,$(image)))) + +.PHONY: push +push: images-development ## ** Pushes ALL docker images to ECR. +images-development: $(foreach image,$(IMAGES),push-$(image)) + +define push_image +.PHONY: push-$1 +## Pushes the docker image for a given service to AWS ECR. +push-$1: image-$1 + @test -z "$(CI)" || echo "##[group]Pushing $(strip $(call get_last_element,$(subst .,,$1))) image." + docker tag $(if $(filter $1,$(PROJECT)),$1,$(PROJECT)/$(strip $(call get_last_element,$1))):$(COMMIT) $(PROJECT)/$(strip $(ECR))/$(strip $(call get_last_element,$(subst .,,$1))):$(COMMIT) + docker tag $(if $(filter $1,$(PROJECT)),$1,$(PROJECT)/$(strip $(call get_last_element,$1))):latest $(PROJECT)/$(strip $(ECR))/$(strip $(call get_last_element,$(subst .,,$1))):latest + docker push $(PROJECT)/$(strip $(ECR))/$(strip $(call get_last_element,$(subst .,,$1))):$(COMMIT) + docker push $(PROJECT)/$(strip $(ECR))/$(strip $(call get_last_element,$(subst .,,$1))):latest + @test -z "$(CI)" || echo "##[endgroup]" +endef +$(foreach image,$(IMAGES),$(eval $(call push_image,$(image)))) + +.PHONY: pull +pull: $(foreach image,$(IMAGES),pull-$(image)) ## ** Pulls ALL docker images for every service. + +define pull_image +.PHONY: pull-$1 +## For the given service, pulls the associated docker image from AWS ECR. +pull-$1: + docker pull $(strip $(ECR))/$(strip $(call get_last_element,$(subst .,,$1))):$(COMMIT) +endef +$(foreach image,$(IMAGES),$(eval $(call pull_image,$(image)))) + +# ┌┬┐┌─┐┌─┐┬ ┌─┐┬ ┬ +# ││├┤ ├─┘│ │ │└┬┘ +# ─┴┘└─┘┴ ┴─┘└─┘ ┴ + +.PHONY: auth-aws +auth-aws: ## Checks current auth to AWS; An error indicates an issue with auth to an AWS account. + @aws sts get-caller-identity &>/dev/null + +# Sets PRIMARY_SERVICES to be SERVICES, so you can use either in a Makefile. +PRIMARY_SERVICES ?= $(SERVICES) + +.PHONY: deploy $(PRIMARY_SERVICES) $(SECONDARY_SERVICES) $(TERTIARY_SERVICES) $(QUATERNARY_SERVICES) $(QUINARY_SERVICES) +deploy: $(PRIMARY_SERVICES) $(SECONDARY_SERVICES) $(TERTIARY_SERVICES) $(QUATERNARY_SERVICES) $(QUINARY_SERVICES) ## ** Deploys the Cloudformation template for ALL services. + +## Deploys the Cloudformation template for the given service. +deploy-%: cf/%/package.yml +ifndef ENVIRONMENT + $(error ENVIRONMENT not defined; please populate it before deploying) +else + @test -z "$(CI)" || echo "##[group]Deploying $*." + aws cloudformation deploy \ + --region $(AWS_REGION) \ + --template-file $< \ + $(shell [[ $(FILE_SIZE) -ge 51200 ]] && echo "--s3-bucket $(BUCKET)") \ + --stack-name $(STACK_NAME) \ + --tags repository=$(REPO) project=$(PROJECT) component=$* revision=$(COMMIT) \ + $(if $(ADDITIONAL_STACK_TAGS),$(ADDITIONAL_STACK_TAGS),) \ + --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND \ + --parameter-overrides Component=$* Revision=$(COMMIT) Environment=$(ENVIRONMENT) \ + $(if $(wildcard cf/.params/$(ENVIRONMENT).json),$(shell jq -r 'map("\(.ParameterKey)=\(.ParameterValue)") | join(" ")' ./cf/.params/$(ENVIRONMENT).json),) \ + $(if $(ADDITIONAL_PARAMETER_OVERRIDES),$(ADDITIONAL_PARAMETER_OVERRIDES),) \ + --no-fail-on-empty-changeset +endif + +## Packages the Cloudformation template for the given service. +cf/%/package.yml: cf/%/template.yml +ifndef ENVIRONMENT + $(error ENVIRONMENT not defined; please populate it before deploying) +else + @test -z "$(CI)" || echo "##[group]Packaging $*." + aws cloudformation package \ + --region $(AWS_REGION) \ + --template-file $< \ + --output-template-file $@ \ + --s3-prefix $(PROJECT) \ + --s3-bucket $(BUCKET) + @test -z "$(CI)" || echo "##[endgroup]" +endif + +# ┌┬┐┬┌─┐┌─┐ +# ││││└─┐│ +# ┴ ┴┴└─┘└─┘ + +.PHONY: generate-readme +generate-readme: ## Generates a README.md, using a template. + @bin/README.sh jmpa-io + +.PHONY: update-template +update-template: ## Pulls changes from root-template into this repository. + git fetch template + git merge template/main --allow-unrelated-histories + +.PHONY: clean +clean: ## Removes generated files and folders, resetting this repository back to its initial clone state. + @test -z "$(CI)" || echo "##[group]Cleaning up." + @rm -f coverage.* traces.* + @rm -rf dist + @test -z "$(CI)" || echo "##[endgroup]" + +.PHONY: help +help: ## Prints this help page. + @echo "Available targets:" + @awk_script='\ + /^[a-zA-Z\-\_0-9%\/$$]+:/ { \ + target = $$1; \ + gsub("\\$$1", "%", target); \ + nb = sub(/^## /, "", helpMessage); \ + if (nb == 0) { \ + helpMessage = $$0; \ + nb = sub(/^[^:]*:.* ## /, "", helpMessage); \ + } \ + if (nb) print "\033[33m" target "\033[0m" helpMessage; \ + } { helpMessage = $$0 } \ + '; \ + awk "$$awk_script" $(MAKEFILE_LIST) | column -ts: + +# ┬ ┬┌─┐┌┬┐ +# │ │└─┐ │ +# ┴─┘┴└─┘ ┴ + +.PHONY: list-sh +list-sh: # Lists ALL shell scripts under the current directory. + @echo $(SH_FILES) + +.PHONY: list-go +list-go: # Lists ALL Go files under the current directory. + @echo $(GO_FILES) + +.PHONY: list-cf +list-cf: # Lists ALL dirs under ./cf. + @echo $(CF_DIRS) + +.PHONY: list-cmd +list-cmd: # Lists ALL dirs under ./cmd. + @echo $(CMD_DIRS) + +.PHONY: list-binaries +list-binaries: # Lists ALL binary targets and their output directories. + @echo $(BINARIES_TARGETS) + @echo $(BINARIES_OUTPUT_DIRECTORIES) + +.PHONY: list-images +list-images: # Lists ALL docker images for every service. + @echo $(IMAGES) + +.PHONY: list-deploy +list-deploy: # Lists ALL services to deploy. + @echo $(PRIMARY_SERVICES) + @echo $(SECONDARY_SERVICES) + @echo $(TERTIARY_SERVICES) + @echo $(QUATERNARY_SERVICES) + @echo $(QUINARY_SERVICES) + +.PHONY: list-deploy +list-submodules: # Lists ALL submodules. + @echo $(SUBMODULES) + +# ┌┐┌┌─┐┌┬┐┌─┐┌─┐ +# ││││ │ │ ├┤ └─┐ +# ┘└┘└─┘ ┴ └─┘└─┘ + +# ASCII art in this file are generated from: https://patorjk.com/software/taag/#p=display&h=0&v=0&f=Calvin%20S&t=notes%0A From e17d936b308fa01ba6900828c4e47713641f3366 Mon Sep 17 00:00:00 2001 From: jcleal Date: Tue, 16 Apr 2024 10:38:28 +1000 Subject: [PATCH 11/19] add a dependabot automerge workflow --- .github/workflows/dependabot-automerge.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100755 .github/workflows/dependabot-automerge.yml diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml new file mode 100755 index 0000000..f2f356d --- /dev/null +++ b/.github/workflows/dependabot-automerge.yml @@ -0,0 +1,18 @@ +--- +name: Dependabot auto-merge +on: + pull_request: + types: [opened, synchronize] + repository_dispatch: + types: [update] + +permissions: + contents: write + pull-requests: write + checks: read + statuses: read + +jobs: + dependabot-automerge: + if: startsWith(github.head_ref, 'dependabot/') + uses: jmpa-io/roots/.github/workflows/dependabot-automerge.yml@main From 038402989ffd85b3e376025467973264b0e0a867 Mon Sep 17 00:00:00 2001 From: jcleal Date: Tue, 16 Apr 2024 00:39:49 +0000 Subject: [PATCH 12/19] [skip ci] Updated README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c2ee7bd..9c22be2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ [![README.yml](https://github.com/jmpa-io/root-template/actions/workflows/README.yml/badge.svg)](https://github.com/jmpa-io/root-template/actions/workflows/README.yml) [![cicd.yml](https://github.com/jmpa-io/root-template/actions/workflows/cicd.yml/badge.svg)](https://github.com/jmpa-io/root-template/actions/workflows/cicd.yml) +[![dependabot-automerge.yml](https://github.com/jmpa-io/root-template/actions/workflows/dependabot-automerge.yml/badge.svg)](https://github.com/jmpa-io/root-template/actions/workflows/dependabot-automerge.yml) # `root-template` From 4d2475c61d9ec7a6f618a040cc456a7b15280215 Mon Sep 17 00:00:00 2001 From: jcleal Date: Fri, 31 May 2024 09:30:07 +0200 Subject: [PATCH 13/19] update dependabot-automerge repository dispatch event to be more specific --- .github/workflows/dependabot-automerge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml index f2f356d..96ccb11 100755 --- a/.github/workflows/dependabot-automerge.yml +++ b/.github/workflows/dependabot-automerge.yml @@ -4,7 +4,7 @@ on: pull_request: types: [opened, synchronize] repository_dispatch: - types: [update] + types: [update-dependabot-automerge] permissions: contents: write From 7852d889c5e375e1fe41361600e91e4a902c077f Mon Sep 17 00:00:00 2001 From: jcleal Date: Fri, 31 May 2024 09:36:52 +0200 Subject: [PATCH 14/19] fix an issue with the regex for this machine, we'll see how it works on the others later --- Makefile.common.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.common.mk b/Makefile.common.mk index e7ce90e..a4099b6 100644 --- a/Makefile.common.mk +++ b/Makefile.common.mk @@ -338,7 +338,7 @@ clean: ## Removes generated files and folders, resetting this repository back to help: ## Prints this help page. @echo "Available targets:" @awk_script='\ - /^[a-zA-Z\-\_0-9%\/$$]+:/ { \ + /^[a-zA-Z\-\\_0-9%\/$$]+:/ { \ target = $$1; \ gsub("\\$$1", "%", target); \ nb = sub(/^## /, "", helpMessage); \ From 436d70cb60f002a0b743715f2b89fb7491a8bcc8 Mon Sep 17 00:00:00 2001 From: jcleal Date: Fri, 31 May 2024 11:35:53 +0200 Subject: [PATCH 15/19] add new line after Makefile --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 9d21e20..84440e5 100644 --- a/Makefile +++ b/Makefile @@ -4,3 +4,4 @@ PROJECT = root-template # include common targets. include Makefile.common.mk + From 6b07f738223c1d470e98529edd7996701a6ff1f3 Mon Sep 17 00:00:00 2001 From: jcleal Date: Tue, 11 Jun 2024 17:55:44 +0200 Subject: [PATCH 16/19] update the root-template to reflect changes in pipelines --- .github/workflows/README.yml | 7 +- .github/workflows/cicd.yml | 22 +- .github/workflows/dependabot-automerge.yml | 4 +- Makefile | 20 +- Makefile.common.mk | 339 +++++++++++++++------ 5 files changed, 281 insertions(+), 111 deletions(-) diff --git a/.github/workflows/README.yml b/.github/workflows/README.yml index 9e9676a..33c3eb8 100644 --- a/.github/workflows/README.yml +++ b/.github/workflows/README.yml @@ -17,11 +17,12 @@ permissions: jobs: generate-readme: - uses: jmpa-io/roots/.github/workflows/README.yml@main + uses: jmpa-io/pipelines/.github/workflows/00-README.yml@main secrets: inherit post-to-slack: needs: [generate-readme] if: always() - uses: jmpa-io/roots/.github/workflows/post-to-slack.yml@main - secrets: inherit + uses: jmpa-io/pipelines/.github/workflows/99-post-to-slack.yml@main + secrets: + WEBHOOK: ${{ secrets.SLACK_GITHUB_NOTIFICATIONS_WEBHOOK }} diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index 3d90371..fe24e81 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -21,15 +21,25 @@ permissions: jobs: lint: - uses: jmpa-io/roots/.github/workflows/lint.yml@main - secrets: inherit + uses: jmpa-io/pipelines/.github/workflows/10-lint.yml@main + secrets: + AWS_REGION: ${{ secrets.AWS_REGION }} + AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }} + AWS_RUNNER_ROLE_NAME: ${{ secrets.AWS_RUNNER_ROLE_NAME }} + ADMIN_GITHUB_TOKEN: ${{ secrets.ADMIN_GITHUB_TOKEN }} test: - uses: jmpa-io/roots/.github/workflows/test.yml@main - secrets: inherit + uses: jmpa-io/pipelines/.github/workflows/20-test.yml@main + secrets: + AWS_REGION: ${{ secrets.AWS_REGION }} + AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }} + AWS_RUNNER_ROLE_NAME: ${{ secrets.AWS_RUNNER_ROLE_NAME }} + ADMIN_GITHUB_TOKEN: ${{ secrets.ADMIN_GITHUB_TOKEN }} post-to-slack: needs: [lint, test] if: always() - uses: jmpa-io/roots/.github/workflows/post-to-slack.yml@main - secrets: inherit + uses: jmpa-io/pipelines/.github/workflows/99-post-to-slack.yml@main + secrets: + WEBHOOK: ${{ secrets.SLACK_GITHUB_NOTIFICATIONS_WEBHOOK }} + diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml index 96ccb11..c90278c 100755 --- a/.github/workflows/dependabot-automerge.yml +++ b/.github/workflows/dependabot-automerge.yml @@ -1,5 +1,5 @@ --- -name: Dependabot auto-merge +name: Dependabot Auto-merge on: pull_request: types: [opened, synchronize] @@ -15,4 +15,4 @@ permissions: jobs: dependabot-automerge: if: startsWith(github.head_ref, 'dependabot/') - uses: jmpa-io/roots/.github/workflows/dependabot-automerge.yml@main + uses: jmpa-io/pipelines/.github/workflows/00-dependabot-automerge.yml@main diff --git a/Makefile b/Makefile index 84440e5..0f16d6f 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,21 @@ -PROJECT = root-template +# Default PROJECT, if not given by another Makefile. +ifndef PROJECT +PROJECT=root-template +endif + +# Services. +SERVICES = +# TODO: fill these out with services to deploy. + +# Targets: +# TODO: fill these out with Make targets. ---: ## --- -# include common targets. -include Makefile.common.mk +# Includes the common Makefile. +# NOTE: this recursively goes back and finds the `.git` directory and assumes +# this is the root of the project. This could have issues when this assumtion +# is incorrect. +include $(shell while [[ ! -d .git ]]; do cd ..; done; pwd)/Makefile.common.mk + diff --git a/Makefile.common.mk b/Makefile.common.mk index a4099b6..5508bd3 100644 --- a/Makefile.common.mk +++ b/Makefile.common.mk @@ -1,79 +1,183 @@ + # -# This Makefile is generic across all repositories: +# This Makefile is generic across ALL repositories: # https://github.com/jmpa-io/root-template/blob/main/Makefile.common.mk # # See the bottom for additional notes. # -# Check project variables are given. +# The name of the project. ifndef PROJECT $(error PROJECT not defined, missing from Makefile?) endif -# Variables. -SHELL = /bin/sh # The shell to use for executing commands. -ENVIRONMENT ?= dev # The environment to deploy to. -COMMIT = $(shell git describe --tags --always) # The git commit hash. -REPO = $(shell basename $(shell git rev-parse --show-toplevel)) # The name of the repository. -COMMA := , # Used for if conditions in Make where a comma is needed. -OS := $(shell uname | tr '[:upper:]' '[:lower:]') # The operating system the Makefile is being executed on. -BUILDING_OS ?= $(OS) # The operating system used when building binaries. -SUPPORTED_OPERATING_SYSTEMS = linux,darwin # A list of operating systems that can be used when building binaries. - -# Setup OS specific variables. +# The default command executed when running `make`. +.DEFAULT_GOAL:= help + +# +# ┬ ┬┌─┐┬─┐┬┌─┐┌┐ ┬ ┌─┐┌─┐ +# └┐┌┘├─┤├┬┘│├─┤├┴┐│ ├┤ └─┐ +# └┘ ┴ ┴┴└─┴┴ ┴└─┘┴─┘└─┘└─┘o +# + +# The shell used for executing commands. +SHELL = /bin/sh + +# The environment used when deploying; This can affect which config is used when deploying. +ENVIRONMENT ?= dev # The environment to deploy to. + +# The git commit hash. +COMMIT = $(shell git describe --tags --always) + +# The name of this repository. +REPO = $(shell basename $(shell git rev-parse --show-toplevel)) + +# The name of the GitHub organization commonly used. +ORG ?= jmpa-io + +# The operating system this Makefile is being executed on. +OS := $(shell uname | tr '[:upper:]' '[:lower:]') + +# The operating system used when building binaries. +BUILDING_OS ?= $(OS) + +# A comma separated list of operating systems that can be used when building binaries. +SUPPORTED_OPERATING_SYSTEMS = linux,darwin + +# Used for 'if' conditions in Make where a comma is needed. +COMMA := , + +# Linux specific variables. ifeq ($(OS),linux) - SED_FLAGS = -i - FILE_SIZE = $(shell stat -c '%s' $<) + + # Flags used when doing certain 'sed' commands. + SED_FLAGS = -i + + # Command used to determine the size of a given file. + FILE_SIZE = $(shell stat -c '%s' $<) + +# Darwin specific variables. else ifeq ($(OS),darwin) - SED_FLAGS = -i '' - FILE_SIZE = $(shell stat -f '%z' $<) + + # Flags used when doing certain 'sed' commands. + SED_FLAGS = -i '' + + # Command used to determine the size of a given file. + FILE_SIZE = $(shell stat -f '%z' $<) + endif -# Files + Directories. -SH_FILES := $(shell find . $(IGNORE_SUBMODULES) -name "*.sh" -type f 2>/dev/null) -GO_FILES := $(shell find . $(IGNORE_SUBMODULES) -name "*.go" -type f 2>/dev/null) -CF_FILES := $(shell find ./cf $(IGNORE_SUBMODULES) -name 'template.yml' -type f 2>/dev/null) -SAM_FILES := $(shell find ./cf $(IGNORE_SUBMODULES) -name 'template.yaml' -type f 2>/dev/null) -CF_DIRS := $(shell find ./cf $(IGNORE_SUBMODULES) -mindepth 1 -maxdepth 1 -type d 2>/dev/null) -CMD_DIRS := $(shell find ./cmd $(IGNORE_SUBMODULES) -mindepth 1 -maxdepth 1 -type d 2>/dev/null) -IMAGES := $(patsubst .,$(PROJECT),$(patsubst ./%,%,$(shell find . -name 'Dockerfile' -type f -exec dirname {} \; 2>/dev/null))) +# ---- Files & Directories ---- + +# A list of shell scripts under ALL paths (except submodules) in this repository. +SH_FILES := $(shell find . $(IGNORE_SUBMODULES) -name "*.sh" -type f 2>/dev/null) + +# A list of Go files under ALL paths (except submodules) in this repository. +GO_FILES := $(shell find . $(IGNORE_SUBMODULES) -name "*.go" -type f 2>/dev/null) + +# A list of Cloudformation templates under './cf' (except submodules) in this repository. +CF_FILES := $(shell find ./cf $(IGNORE_SUBMODULES) -name 'template.yml' -type f 2>/dev/null) + +# A list of SAM templates under './cf' (except submodules) in this repository. +SAM_FILES := $(shell find ./cf $(IGNORE_SUBMODULES) -name 'template.yaml' -type f 2>/dev/null) + +# A list of directories under './cf' (except submodules) housing Cloudformation templates. +CF_DIRS := $(shell find ./cf $(IGNORE_SUBMODULES) -mindepth 1 -maxdepth 1 -type d 2>/dev/null) + +# A list of workflows under '.github/workflows' (except submodules) in this repository. +WORKFLOW_FILES := $(shell find .github/workflows $(IGNORE_SUBMODULES) -mindepth 1 -maxdepth 1 -name '*.yml' -type f 2>/dev/null) + +# A list of Dockerfiles under ALL paths (except submodules) in this repository. +IMAGES := $(patsubst .,$(PROJECT),$(patsubst ./%,%,$(shell find . -name 'Dockerfile' -type f -exec dirname {} \; 2>/dev/null))) + +# A list of directories under './cmd' that contain 'main.go'. +CMD_DIRS = $(shell find cmd/* -name main.go -maxdepth 1 -type f -exec dirname {} \; 2>/dev/null | awk -F/ '{$$1=""; sub(/^ /, ""); print $$0}') -# Submodules. +# Adds 'cmd/' to each directory found under $(CMD_DIRS). +CMD_SOURCE = $(addprefix cmd/,$(CMD_DIRS)) + +# Adds 'binary-' to each directory found under $(CMD_DIRS). +BINARIES_TARGETS = $(addprefix binary-,$(CMD_DIRS)) + +# Adds 'dist/' to each directory found under $(CMD_DIRS). +BINARIES_OUTPUT_DIRECTORIES = $(addprefix dist/,$(CMD_DIRS)) + +# ---- Submodules ---- + +# The paths to any given submodules found in this repository. SUBMODULES := $(shell git config --file $(shell while [[ ! -d .git ]]; do cd ..; done; pwd)/.gitmodules --get-regexp path | awk '{ print $$2 }') + +# A space separated list of submodules to ignore when using 'find' commands in +# this Makefile. IGNORE_SUBMODULES = $(foreach module,$(SUBMODULES),-not \( -path "./$(module)" -o -path "./$(module)/*" \)) -# Binaries. -CMD_DIRS = $(shell find cmd/* -name main.go -maxdepth 1 -type f -exec dirname {} \; 2>/dev/null | awk -F/ '{$$1=""; sub(/^ /, ""); print $$0}') -CMD_SOURCE = $(addprefix cmd/,$(CMD_DIRS)) -BINARIES_TARGETS = $(addprefix binary-,$(CMD_DIRS)) -BINARIES_OUTPUT_DIRECTORIES = $(addprefix dist/,$(CMD_DIRS)) +# ---- AWS ---- + +# The region used when deploying a Cloudformation stack, or doing some things +# via the aws-cli, in the authed AWS account. +AWS_REGION ?= ap-southeast-2 + +# The Cloudformation stack name used when deploying a Cloudformation stack to +# the authed AWS account. +STACK_NAME = $(PROJECT)-$* + +# The id of the authed AWS account. +AWS_ACCOUNT_ID ?= $(shell aws sts get-caller-identity --query 'Account' --output text) -# AWS. -AWS_REGION ?= ap-southeast-2 -STACK_NAME = $(PROJECT)-$* -AWS_ACCOUNT_ID ?= $(shell aws sts get-caller-identity --query 'Account' --output text) -ECR = $$(AWS_ACCOUNT_ID).dkr.ecr.$(AWS_REGION).amazonaws.com -BUCKET ?= jmpa-io-artifacts +# The default path to an AWS ECR repository for the authed AWS account. +ECR = $$(AWS_ACCOUNT_ID).dkr.ecr.$(AWS_REGION).amazonaws.com -# Funcs. -get_last_element = $(lastword $(subst /, ,$1)) # Splits a string by '/' and retrieves the last element in the given array. +# The name of a generic S3 bucket in the authed AWS account. +# TODO: should this be an AWS SSM Parameter Store path? +BUCKET ?= $(ORG)-artifacts + +# +# ┌─┐┬ ┬┌┐┌┌─┐┌┬┐┬┌─┐┌┐┌┌─┐ +# ├┤ │ │││││ │ ││ ││││└─┐ +# └ └─┘┘└┘└─┘ ┴ ┴└─┘┘└┘└─┘o +# + +# Splits a string by '/' and retrieves the last element in the given array. +get_last_element = $(lastword $(subst /, ,$1)) + +# +# ┌┬┐┌─┐┌─┐┌─┐┌┐┌┌┬┐┌─┐┌┐┌┌─┐┬┌─┐┌─┐ +# ││├┤ ├─┘├┤ │││ ││├┤ ││││ │├┤ └─┐ +# ─┴┘└─┘┴ └─┘┘└┘─┴┘└─┘┘└┘└─┘┴└─┘└─┘o +# -# Check deps. ifndef CI -EXECUTABLES ?= awk aws cfn-lint column find go golangci-lint grep hadolint sam zip +EXECUTABLES ?= \ + awk \ + aws \ + cfn-lint \ + column \ + find \ + go \ + golangci-lint \ + grep \ + hadolint \ + sam \ + zip MISSING := $(strip $(foreach bin,$(EXECUTABLES),$(if $(shell command -v $(bin) 2>/dev/null),,$(bin)))) $(if $(MISSING),$(error Please install: $(MISSING))) endif -# The default command executed when running `make`. -.DEFAULT_GOAL:= help - -# ┬ ┬ ┌┐┌┌┬┐ -# │ │ │││ │ -# ┴─┘┴ ┘└┘ ┴ +# +# ┬ ┬┌┐┌┌┬┐ +# │ ││││ │ +# ┴─┘┴┘└┘ ┴ o +# .PHONY: lint -lint: lint-sh lint-go lint-cf lint-sam lint-docker ## ** Lints everything. +lint: ## ** Lints everything. +lint: \ + lint-sh \ + lint-go \ + lint-cf \ + lint-sam \ + lint-docker \ + lint-workflows .PHONY: lint-sh lint-sh: ## Lints shell files. @@ -125,19 +229,34 @@ else endif @test -z "$(CI)" || echo "##[endgroup]" +.PHONY: lint-workflows +lint-workflows: ## Lints GitHub Action workflows. + @test -z "$(CI)" || echo "##[group]Linting GitHub Action workflows." +ifeq ($(WORKFLOW_FILES),) + @echo "No GitHub Action workflows to lint." +else + find .github/workflows -mindepth 1 -maxdepth 1 -name '*.yml' -type f -exec actionlint '{}' \; || true +endif + @test -z "$(CI)" || echo "##[endgroup]" + +# # ┌┬┐┌─┐┌─┐┌┬┐ # │ ├┤ └─┐ │ -# ┴ └─┘└─┘ ┴ +# ┴ └─┘└─┘ ┴ o +# .PHONY: test -test: test-go ## ** Tests everything. +test: ## ** Tests everything. +test: \ + test-go .PHONY: test-go -test-go: dist/coverage.txt ## Runs Go tests. +test-go: ## Runs Go tests. +test-go: dist/coverage.txt dist/coverage.txt: dist @test -z "$(CI)" || echo "##[group]Unit tests." ifeq ($(GO_FILES),) - @echo "No *.go files to test." + @echo "No *.go files to test or generate code-coverage." else @go version CGO_ENABLED=1 go test -short -coverprofile=$@ \ @@ -146,7 +265,8 @@ endif @test -z "$(CI)" || echo "##[endgroup]" .PHONY: code-coverage -code-coverage: dist/coverage.txt ## Generates a Go code coverage report, broken-down by function, to stdout. +code-coverage: ## Generate a Go code coverage report, broken down by function. +code-coverage: dist/coverage.txt @if [[ -f $< ]]; then \ test -z "$(CI)" || echo "##[group]Code coverage."; \ go tool cover -func=$<; \ @@ -154,18 +274,24 @@ code-coverage: dist/coverage.txt ## Generates a Go code coverage report, broken- fi .PHONY: code-coverage-html -code-coverage-html: dist/coverage.txt ## Generates a Go code HTML coverage report, rendered in the default browser. +code-coverage-html: ## Generate a Go code HTML coverage report, rendered in the default browser. +code-coverage-html: dist/coverage.txt @if [[ -f $< ]]; then \ go tool cover -html=$<; \ fi +# # ┌┐ ┬┌┐┌┌─┐┬─┐┬┌─┐┌─┐ # ├┴┐││││├─┤├┬┘│├┤ └─┐ -# └─┘┴┘└┘┴ ┴┴└─┴└─┘└─┘ +# └─┘┴┘└┘┴ ┴┴└─┴└─┘└─┘o +# -.PHONY: binaries binaries-all -binaries: $(BINARIES_TARGETS) ## ** Builds ALL binaries for the $(BUILDING_OS) environment. -binaries-all: ## ** Builds ALL binaries for ALL supported operating systems. +.PHONY: binaries +binaries: ## ** Builds binaries only for the environment of the $(BUILDING_OS) operating system. +binaries: $(BINARIES_TARGETS) + +.PHONY: binaries-all +binaries-all: ## ** Builds binaries for ALL supported operating systems under $(SUPPORTED_OPERATING_SYSTEMS). @for os in $(shell echo $(SUPPORTED_OPERATING_SYSTEMS) | tr ',' ' '); do \ $(MAKE) --no-print-directory BUILDING_OS=$$os binaries; \ done @@ -204,28 +330,33 @@ define build_binary @test -z "$(CI)" || echo "##[endgroup]" endef -## Builds a binary, for the given service, for the $(BUILDING_OS) environment. +binary-%: ## Builds a binary, for the given service, for the $(BUILDING_OS) environment. binary-%: cmd/%/main.go dist/% $(call build_binary,$(BUILDING_OS)) +# # ┬ ┌─┐┌┬┐┌┐ ┌┬┐┌─┐ # │ ├─┤│││├┴┐ ││├─┤ -# ┴─┘┴ ┴┴ ┴└─┘─┴┘┴ ┴ +# ┴─┘┴ ┴┴ ┴└─┘─┴┘┴ ┴ o +# # Moves the bootstrap, for the given service, into the dist directory. bootstrap-%: dist/% cmd/%/bootstrap @cp cmd/$*/bootstrap dist/$*/ -# Invokes the given service locally, if able. +invoke-%: ## Invokes the given service locally, using aws-sam-cli, if able. invoke-%: cmd/%/local.sh binary-% bootstrap-% @$< +# # ┌┬┐┌─┐┌─┐┬┌─┌─┐┬─┐ # │││ ││ ├┴┐├┤ ├┬┘ -# ─┴┘└─┘└─┘┴ ┴└─┘┴└─ +# ─┴┘└─┘└─┘┴ ┴└─┘┴└─ o +# .PHONY: images -images: $(foreach image,$(IMAGES),image-$(image)) ## ** Builds ALL docker images for each service. +images: ## ** Builds ALL docker images for each services. +images: $(foreach image,$(IMAGES),image-$(image)) define build_image .PHONY: image-$1 @@ -238,7 +369,8 @@ endef $(foreach image,$(IMAGES),$(eval $(call build_image,$(image)))) .PHONY: push -push: images-development ## ** Pushes ALL docker images to ECR. +push: ## ** Pushes ALL docker images to AWS ECR. +push: images-development images-development: $(foreach image,$(IMAGES),push-$(image)) define push_image @@ -246,16 +378,17 @@ define push_image ## Pushes the docker image for a given service to AWS ECR. push-$1: image-$1 @test -z "$(CI)" || echo "##[group]Pushing $(strip $(call get_last_element,$(subst .,,$1))) image." - docker tag $(if $(filter $1,$(PROJECT)),$1,$(PROJECT)/$(strip $(call get_last_element,$1))):$(COMMIT) $(PROJECT)/$(strip $(ECR))/$(strip $(call get_last_element,$(subst .,,$1))):$(COMMIT) - docker tag $(if $(filter $1,$(PROJECT)),$1,$(PROJECT)/$(strip $(call get_last_element,$1))):latest $(PROJECT)/$(strip $(ECR))/$(strip $(call get_last_element,$(subst .,,$1))):latest - docker push $(PROJECT)/$(strip $(ECR))/$(strip $(call get_last_element,$(subst .,,$1))):$(COMMIT) - docker push $(PROJECT)/$(strip $(ECR))/$(strip $(call get_last_element,$(subst .,,$1))):latest + docker tag $(if $(filter $1,$(PROJECT)),$1,$(PROJECT)/$(strip $(call get_last_element,$1))):$(COMMIT) $(strip $(ECR))/$(strip $(call get_last_element,$(subst .,,$1))):$(COMMIT) + docker tag $(if $(filter $1,$(PROJECT)),$1,$(PROJECT)/$(strip $(call get_last_element,$1))):latest $(strip $(ECR))/$(strip $(call get_last_element,$(subst .,,$1))):latest + docker push $(strip $(ECR))/$(strip $(call get_last_element,$(subst .,,$1))):$(COMMIT) + docker push $(strip $(ECR))/$(strip $(call get_last_element,$(subst .,,$1))):latest @test -z "$(CI)" || echo "##[endgroup]" endef $(foreach image,$(IMAGES),$(eval $(call push_image,$(image)))) .PHONY: pull -pull: $(foreach image,$(IMAGES),pull-$(image)) ## ** Pulls ALL docker images for every service. +pull: ## ** Pulls ALL docker images for every service from AWS ECR. +pull: $(foreach image,$(IMAGES),pull-$(image)) define pull_image .PHONY: pull-$1 @@ -265,21 +398,25 @@ pull-$1: endef $(foreach image,$(IMAGES),$(eval $(call pull_image,$(image)))) +# # ┌┬┐┌─┐┌─┐┬ ┌─┐┬ ┬ # ││├┤ ├─┘│ │ │└┬┘ -# ─┴┘└─┘┴ ┴─┘└─┘ ┴ - -.PHONY: auth-aws -auth-aws: ## Checks current auth to AWS; An error indicates an issue with auth to an AWS account. - @aws sts get-caller-identity &>/dev/null +# ─┴┘└─┘┴ ┴─┘└─┘ ┴ o +# -# Sets PRIMARY_SERVICES to be SERVICES, so you can use either in a Makefile. +# Sets PRIMARY_SERVICES to be SERVICES, so either can be used in ANY Makefile. PRIMARY_SERVICES ?= $(SERVICES) .PHONY: deploy $(PRIMARY_SERVICES) $(SECONDARY_SERVICES) $(TERTIARY_SERVICES) $(QUATERNARY_SERVICES) $(QUINARY_SERVICES) -deploy: $(PRIMARY_SERVICES) $(SECONDARY_SERVICES) $(TERTIARY_SERVICES) $(QUATERNARY_SERVICES) $(QUINARY_SERVICES) ## ** Deploys the Cloudformation template for ALL services. - -## Deploys the Cloudformation template for the given service. +deploy: ## ** Deploys the Cloudformation template for ALL services. +deploy: \ + $(PRIMARY_SERVICES) \ + $(SECONDARY_SERVICES) \ + $(TERTIARY_SERVICES) \ + $(QUATERNARY_SERVICES) \ + $(QUINARY_SERVICES) + +deploy-%: ## Deploys the Cloudformation template for the given service. deploy-%: cf/%/package.yml ifndef ENVIRONMENT $(error ENVIRONMENT not defined; please populate it before deploying) @@ -297,9 +434,10 @@ else $(if $(wildcard cf/.params/$(ENVIRONMENT).json),$(shell jq -r 'map("\(.ParameterKey)=\(.ParameterValue)") | join(" ")' ./cf/.params/$(ENVIRONMENT).json),) \ $(if $(ADDITIONAL_PARAMETER_OVERRIDES),$(ADDITIONAL_PARAMETER_OVERRIDES),) \ --no-fail-on-empty-changeset + @test -z "$(CI)" || echo "##[endgroup]" endif -## Packages the Cloudformation template for the given service. +cf/%/package.yml: ## Packages the Cloudformation template for the given service. cf/%/package.yml: cf/%/template.yml ifndef ENVIRONMENT $(error ENVIRONMENT not defined; please populate it before deploying) @@ -314,21 +452,19 @@ else @test -z "$(CI)" || echo "##[endgroup]" endif +# # ┌┬┐┬┌─┐┌─┐ # ││││└─┐│ -# ┴ ┴┴└─┘└─┘ - -.PHONY: generate-readme -generate-readme: ## Generates a README.md, using a template. - @bin/README.sh jmpa-io +# ┴ ┴┴└─┘└─┘ o +# .PHONY: update-template -update-template: ## Pulls changes from root-template into this repository. +update-template: ## Pulls changes from the pre-defined template into this repository. git fetch template git merge template/main --allow-unrelated-histories .PHONY: clean -clean: ## Removes generated files and folders, resetting this repository back to its initial clone state. +clean: ## Removes generated files & folders, resetting this repository back to its initial clone state. @test -z "$(CI)" || echo "##[group]Cleaning up." @rm -f coverage.* traces.* @rm -rf dist @@ -341,19 +477,29 @@ help: ## Prints this help page. /^[a-zA-Z\-\\_0-9%\/$$]+:/ { \ target = $$1; \ gsub("\\$$1", "%", target); \ - nb = sub(/^## /, "", helpMessage); \ + nb = sub(/^## /, "", helpMsg); \ if (nb == 0) { \ - helpMessage = $$0; \ - nb = sub(/^[^:]*:.* ## /, "", helpMessage); \ + helpMsg = $$0; \ + nb = sub(/^[^:]*:.* ## /, "", helpMsg); \ } \ - if (nb) print "\033[33m" target "\033[0m" helpMessage; \ - } { helpMessage = $$0 } \ + if (nb) print "\033[33m" target "\033[0m" helpMsg; \ + } { helpMsg = $$0 } \ '; \ awk "$$awk_script" $(MAKEFILE_LIST) | column -ts: +# # ┬ ┬┌─┐┌┬┐ # │ │└─┐ │ -# ┴─┘┴└─┘ ┴ +# ┴─┘┴└─┘ ┴ o +# + +.PHONY: list-project +list-project: # Lists the project name used within the Makefile. + @echo $(PROJECT) + +.PHONY: list-org +list-org: # Lists the GitHub organization used within the Makefile. + @echo $(ORG) .PHONY: list-sh list-sh: # Lists ALL shell scripts under the current directory. @@ -371,6 +517,10 @@ list-cf: # Lists ALL dirs under ./cf. list-cmd: # Lists ALL dirs under ./cmd. @echo $(CMD_DIRS) +.PHONY: list-workflows +list-workflows: # Lists ALL workflows under the '.github/workflows' directory. + @echo $(WORKFLOW_FILES) + .PHONY: list-binaries list-binaries: # Lists ALL binary targets and their output directories. @echo $(BINARIES_TARGETS) @@ -392,8 +542,3 @@ list-deploy: # Lists ALL services to deploy. list-submodules: # Lists ALL submodules. @echo $(SUBMODULES) -# ┌┐┌┌─┐┌┬┐┌─┐┌─┐ -# ││││ │ │ ├┤ └─┐ -# ┘└┘└─┘ ┴ └─┘└─┘ - -# ASCII art in this file are generated from: https://patorjk.com/software/taag/#p=display&h=0&v=0&f=Calvin%20S&t=notes%0A From 047f1bed09650eb4a923d38eabc5af4658fbcd13 Mon Sep 17 00:00:00 2001 From: jcleal Date: Wed, 12 Jun 2024 11:24:19 +0200 Subject: [PATCH 17/19] change name of dependabot-automerge --- .github/workflows/dependabot-automerge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml index c90278c..f8dbc5e 100755 --- a/.github/workflows/dependabot-automerge.yml +++ b/.github/workflows/dependabot-automerge.yml @@ -1,5 +1,5 @@ --- -name: Dependabot Auto-merge +name: Dependabot | Auto-merge on: pull_request: types: [opened, synchronize] From 85c4ce97fb02a8566d7e761291e01e7b1523f0b9 Mon Sep 17 00:00:00 2001 From: jcleal Date: Wed, 12 Jun 2024 11:26:57 +0200 Subject: [PATCH 18/19] change : to . --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0f16d6f..0e17f87 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ endif SERVICES = # TODO: fill these out with services to deploy. -# Targets: +# Targets. # TODO: fill these out with Make targets. ---: ## --- From ef0f038545376277ba7dbd1884f1b9000a292f05 Mon Sep 17 00:00:00 2001 From: jcleal Date: Wed, 12 Jun 2024 18:59:45 +0200 Subject: [PATCH 19/19] remove unneccessary spaces --- Makefile.common.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.common.mk b/Makefile.common.mk index 5508bd3..a3e5273 100644 --- a/Makefile.common.mk +++ b/Makefile.common.mk @@ -105,11 +105,11 @@ BINARIES_OUTPUT_DIRECTORIES = $(addprefix dist/,$(CMD_DIRS)) # ---- Submodules ---- # The paths to any given submodules found in this repository. -SUBMODULES := $(shell git config --file $(shell while [[ ! -d .git ]]; do cd ..; done; pwd)/.gitmodules --get-regexp path | awk '{ print $$2 }') +SUBMODULES := $(shell git config --file $(shell while [[ ! -d .git ]]; do cd ..; done; pwd)/.gitmodules --get-regexp path | awk '{ print $$2 }') # A space separated list of submodules to ignore when using 'find' commands in # this Makefile. -IGNORE_SUBMODULES = $(foreach module,$(SUBMODULES),-not \( -path "./$(module)" -o -path "./$(module)/*" \)) +IGNORE_SUBMODULES = $(foreach module,$(SUBMODULES),-not \( -path "./$(module)" -o -path "./$(module)/*" \)) # ---- AWS ----