Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .mk/.mk-common-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
leinardi/make-common@v1 a5d37077c784b7e0ded1faf17ce70ae97ec68f8c
16 changes: 16 additions & 0 deletions .mk/help.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
ifndef MK_COMMON_HELP_INCLUDED
MK_COMMON_HELP_INCLUDED := 1

# Only set default if not already set
ifeq ($(.DEFAULT_GOAL),)
.DEFAULT_GOAL := help
endif

.PHONY: help
help: ## Show this help and usage
@awk 'BEGIN {FS=":.*##"} /^[a-zA-Z0-9_\/-]+:.*##/ { printf "%s:%s\n", $$1, $$2 }' $(MAKEFILE_LIST) \
| sort \
| awk 'BEGIN {FS=":"; print "\nTargets:"} { printf " \033[36m%-24s\033[0m %s\n", $$1, $$2 }'
@echo ""

endif # MK_COMMON_HELP_INCLUDED
9 changes: 9 additions & 0 deletions .mk/password.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
ifndef MK_COMMON_PASSWORD_INCLUDED
MK_COMMON_PASSWORD_INCLUDED := 1

.PHONY: password
password: ## Generate a 99-character password (PostgreSQL compatible)
@echo "Generating a 99-character password (PostgreSQL compatible)..."
@env LC_ALL=C tr -dc 'A-Za-z0-9_.-+=,' < /dev/urandom | head -c 99; echo

endif # MK_COMMON_PASSWORD_INCLUDED
32 changes: 32 additions & 0 deletions .mk/pre-commit.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
ifndef MK_COMMON_PRECOMMIT_INCLUDED
MK_COMMON_PRECOMMIT_INCLUDED := 1

.PHONY: check
check: check-installed-pre-commit ## Run pre-commit on all files
@pre-commit run --all-files

.PHONY: check-stage
check-stage: check-installed-pre-commit ## Run pre-commit on the current staging area
@echo "Running pre-commit on current staging area..."
@pre-commit run

.PHONY: pre-commit-install
pre-commit-install: check-installed-pre-commit ## Install pre-commit git hook in this repo
@pre-commit install

.PHONY: pre-commit-autoupdate
pre-commit-autoupdate: check-installed-pre-commit ## Update pre-commit hook versions (immediate)
@pre-commit autoupdate

.PHONY: check-installed-pre-commit
check-installed-pre-commit: # Verify that pre-commit is installed, print install help otherwise
@if ! command -v pre-commit >/dev/null 2>&1; then \
echo "Error: pre-commit is not installed."; \
echo "Install it with:"; \
echo " macOS: brew install pre-commit"; \
echo " Ubuntu: sudo apt install pre-commit"; \
echo " (or) pipx install pre-commit"; \
exit 1; \
fi

endif # MK_COMMON_PRECOMMIT_INCLUDED
116 changes: 27 additions & 89 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,112 +1,50 @@
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
.PHONY: check
check: check-installed-pre-commit
@pre-commit run --all-files
# Resolve repository root (Makefile can live anywhere)
REPO_ROOT := $(shell git rev-parse --show-toplevel 2>/dev/null || pwd)

.PHONY: check-stage
check-stage: check-installed-pre-commit
@echo "Running pre-commit on current staging area..."
pre-commit run
MK_COMMON_REPO ?= leinardi/make-common
MK_COMMON_VERSION ?= v1

.PHONY: check-master-changes
check-master-changes: check-installed-pre-commit
@REF=; \
if git rev-parse --verify --quiet origin/master >/dev/null && \
git merge-base --is-ancestor origin/master HEAD; then \
REF=origin/master; \
elif git rev-parse --verify --quiet master >/dev/null && \
git merge-base --is-ancestor master HEAD; then \
REF=master; \
else \
echo "Error: neither origin/master nor master is an ancestor of HEAD." >&2; \
exit 1; \
fi; \
echo "Running pre-commit on new commits since $$REF..."; \
echo "pre-commit run --from-ref $$REF --to-ref HEAD"; \
pre-commit run --from-ref $$REF --to-ref HEAD

# Task to run shellcheck on all shell scripts
.PHONY: shellcheck
shellcheck: check-installed-pre-commit check-installed-shellcheck
@echo "Running shellcheck..."
pre-commit run shellcheck --all-files

# Task to run prettier on all .yaml and .yaml files
.PHONY: prettier
prettier: check-installed-pre-commit
pre-commit run prettier-yaml --all-files

# Task to run ansible-lint on all playbooks after prettier
.PHONY: ansible-lint
ansible-lint: check-installed-pre-commit
@echo "Running ansible-lint..."
pre-commit run ansible-lint --all-files

.PHONY: actionlint
actionlint: check-installed-pre-commit
@echo "Running actionlint..."
pre-commit run actionlint --all-files
MK_COMMON_DIR := $(REPO_ROOT)/.mk
MK_COMMON_FILES := help.mk pre-commit.mk password.mk

# Task to run yamllint on all playbooks after prettier
.PHONY: yamllint
yamllint: check-installed-pre-commit
@echo "Running yamllint..."
pre-commit run yamllint --all-files
MK_COMMON_BOOTSTRAP_SCRIPT := $(REPO_ROOT)/scripts/bootstrap-mk-common.sh

.PHONY: check-installed-shellcheck
check-installed-shellcheck:
@if ! command -v shellcheck >/dev/null 2>&1; then \
echo "Error: shellcheck is not installed."; \
echo "Install it with:"; \
echo " macOS: brew install shellcheck"; \
echo " Ubuntu: sudo apt-get install -y shellcheck"; \
exit 1; \
fi
# Bootstrap: the script will self-update and fetch the selected .mk snippets
MK_COMMON_BOOTSTRAP := $(shell "$(MK_COMMON_BOOTSTRAP_SCRIPT)" \
"$(MK_COMMON_REPO)" \
"$(MK_COMMON_VERSION)" \
"$(MK_COMMON_DIR)" \
"$(MK_COMMON_FILES)")

.PHONY: check-installed-prettier
check-installed-prettier:
@if ! command -v prettier >/dev/null 2>&1; then \
echo "Error: prettier is not installed."; \
echo "Install it with:"; \
echo " macOS: brew install prettier"; \
echo " Ubuntu: npm install --global prettier"; \
exit 1; \
fi
# Include shared make logic
include $(addprefix $(MK_COMMON_DIR)/,$(MK_COMMON_FILES))

.PHONY: check-installed-pre-commit
check-installed-pre-commit:
@if ! command -v pre-commit >/dev/null 2>&1; then \
echo "Error: pre-commit is not installed."; \
echo "Install it with:"; \
echo " macOS: brew install pre-commit"; \
echo " Ubuntu: pip install pre-commit"; \
exit 1; \
fi
.PHONY: mk-common-update
mk-common-update: ## Check for remote updates of shared .mk files
@echo "[mk] Checking for updates from $(MK_COMMON_REPO)@$(MK_COMMON_VERSION)"
MK_COMMON_UPDATE=1 "$(MK_COMMON_BOOTSTRAP_SCRIPT)" \
"$(MK_COMMON_REPO)" \
"$(MK_COMMON_VERSION)" \
"$(MK_COMMON_DIR)" \
"$(MK_COMMON_FILES)"

.PHONY: install-pre-commit
install-pre-commit: check-installed-pre-commit
@echo "Setting up pre-commit..."
pre-commit install

# Task to generate inventory/group_vars/all.yaml
.PHONY: generate-group-vars
generate-group-vars: check-installed-pre-commit
generate-group-vars: check-installed-pre-commit ## Generate inventory/group_vars/all.yaml
@echo "Generating inventory/group_vars/all.yaml..."
pre-commit run generate-group-vars --all-files

# Task to run ansible-playbook with optional parameters like TAGS, LIMIT, EXTRA_VARS, OTHER_PARAMS

.PHONY: install
install: check-ansible
install: check-ansible ## Run ansible-playbook with optional parameters
@echo "Running ansible-playbook with optional parameters..."
ansible-playbook playbooks/macos-setup.yaml --ask-become-pass $(strip \
$(if $(TAGS),--tags=$(TAGS)) \
$(if $(LIMIT),--limit=$(LIMIT)) \
$(if $(EXTRA_VARS),--extra-vars="$(EXTRA_VARS)") \
$(if $(OTHER_PARAMS),$(OTHER_PARAMS)))

# Check if ansible is installed, and run the ansible installation script if not
.PHONY: check-ansible
check-ansible:
check-ansible: # Check if ansible is installed, and run the ansible installation script if not
@if ! command -v ansible >/dev/null 2>&1; then \
echo "Ansible is not installed, running setup script..."; \
./install_ansible.sh; \
Expand Down
123 changes: 123 additions & 0 deletions scripts/bootstrap-mk-common.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/usr/bin/env bash
set -euo pipefail

MK_REPO="${1:?MK repo (e.g. leinardi/make-common) required}"
VERSION="${2:?version (e.g. v1.2.0 or latest) required}"
MK_DIR="${3:?target .mk directory required}"
FILES="${4:?list of .mk files required}"

# Mode: normal bootstrap vs update
MK_UPDATE_MODE="${MK_COMMON_UPDATE:-0}"

# Resolve repo root (so Makefile can live anywhere in the repo)
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"

SCRIPT_PATH="${REPO_ROOT}/scripts/bootstrap-mk-common.sh"

# Normalise MK_DIR and derive version file
MK_DIR="${MK_DIR%/}"
MK_VERSION_FILE="${MK_DIR}/.mk-common-version"
EXPECTED="${MK_REPO}@${VERSION}"

NEED_REFRESH=0
STORED_EXPECTED=""
STORED_SHA=""
REMOTE_SHA=""

# Read existing version file, if any: format "<repo>@<version> [sha]"
if [[ -f "${MK_VERSION_FILE}" ]]; then
IFS=' ' read -r STORED_EXPECTED STORED_SHA < "${MK_VERSION_FILE}" || true
fi

if [[ "${MK_UPDATE_MODE}" = "1" ]]; then
# ---------------------------------------------------------------------------
# UPDATE MODE: go online, compare remote SHA, refresh only if changed
# ---------------------------------------------------------------------------
REMOTE_URL="https://github.com/${MK_REPO}.git"
REMOTE_SHA="$(git ls-remote "${REMOTE_URL}" "${VERSION}" 2>/dev/null | awk 'NR==1 {print $1}')"

if [[ -z "${REMOTE_SHA}" ]]; then
echo "[mk] ERROR: could not resolve '${VERSION}' in ${REMOTE_URL}" >&2
echo "[mk] Check MK_COMMON_VERSION or your network connection." >&2
exit 1
fi

# Decide if we need to refresh:
# - tag name changed
# - or no stored SHA (first time / old format)
# - or stored SHA != remote SHA (mutable tag/branch moved)
if [[ "${STORED_EXPECTED}" != "${EXPECTED}" ]] \
|| [[ -z "${STORED_SHA}" ]] \
|| [[ "${STORED_SHA}" != "${REMOTE_SHA}" ]]; then
NEED_REFRESH=1
fi

if [[ "${NEED_REFRESH}" -eq 0 ]]; then
echo "[mk] Shared makefiles already up to date for ${EXPECTED} (${REMOTE_SHA})" >&2
exit 0
fi
else
# ---------------------------------------------------------------------------
# NORMAL MODE: only compare tag string + ensure files exist
# ---------------------------------------------------------------------------
if [[ -z "${STORED_EXPECTED}" ]] || [[ "${STORED_EXPECTED}" != "${EXPECTED}" ]]; then
NEED_REFRESH=1
fi

# Also refresh if any requested .mk file is missing
if [[ "${NEED_REFRESH}" -eq 0 ]]; then
for f in ${FILES}; do
if [[ ! -f "${MK_DIR}/${f}" ]]; then
NEED_REFRESH=1
break
fi
done
fi
fi

# ---------------------------------------------------------------------------
# Refresh: update script + .mk files, write version file, re-exec
# ---------------------------------------------------------------------------

if [[ "${NEED_REFRESH}" -eq 1 ]]; then
echo "[mk] Updating bootstrap-mk-common.sh and .mk files from ${MK_REPO}@${VERSION}" >&2
mkdir -p "${REPO_ROOT}/scripts" "${MK_DIR}"

# If we don't already know REMOTE_SHA (normal mode), resolve it now.
# This only happens when we are *already* going online to download files.
if [[ -z "${REMOTE_SHA}" ]]; then
REMOTE_URL="https://github.com/${MK_REPO}.git"
REMOTE_SHA="$(git ls-remote "${REMOTE_URL}" "${VERSION}" 2>/dev/null | awk 'NR==1 {print $1}')"
if [[ -z "${REMOTE_SHA}" ]]; then
echo "[mk] WARNING: could not resolve SHA for ${EXPECTED};" \
"version file will not contain a SHA." >&2
fi
fi

# Fetch the script itself from the tagged ref
curl -fsSL \
"https://raw.githubusercontent.com/${MK_REPO}/${VERSION}/scripts/bootstrap-mk-common.sh" \
-o "${SCRIPT_PATH}"
chmod +x "${SCRIPT_PATH}"

# Fetch all requested .mk files
for f in ${FILES}; do
echo "[mk] Fetching ${f} from ${MK_REPO}@${VERSION}" >&2
curl -fsSL \
"https://raw.githubusercontent.com/${MK_REPO}/${VERSION}/.mk/${f}" \
-o "${MK_DIR}/${f}"
done

# Store "<repo>@<version> <sha>" (sha may be empty only if resolution failed)
if [[ -n "${REMOTE_SHA}" ]]; then
printf '%s %s\n' "${EXPECTED}" "${REMOTE_SHA}" > "${MK_VERSION_FILE}"
else
printf '%s\n' "${EXPECTED}" > "${MK_VERSION_FILE}"
fi

# Re-exec the freshly downloaded script so any new logic applies immediately
exec "${SCRIPT_PATH}" "$@"
fi

# If we reach here in normal mode, script + .mk files are already up to date.
# Nothing else to do; Make just needed us for our side effects.