-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
83 lines (75 loc) · 4.19 KB
/
Copy pathMakefile
File metadata and controls
83 lines (75 loc) · 4.19 KB
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
# AWS layer for tklon.com: infra, publish, deploy, stats.
#
# The site itself is built by the `tklon` binary, not make — see the README:
# cargo run -- build cargo run -- serve
#
# Requires: aws CLI (authenticated, e.g. `aws login`), cargo, and uv (for stats).
STACK ?= tklondotcom
REGION ?= us-east-1
TEMPLATE := deploy/template.yml
# Customizable values live in params.yml — edit there, not in the template
# (which is generic schema). See deploy/params.yml for the format.
PARAMS := deploy/params.yml
# Holds zipped Lambda code uploaded by `cloudformation package`. Created
# idempotently by `infra` — no manual bootstrap needed.
ARTIFACTS_BUCKET ?= $(STACK)-cfn-artifacts
PACKAGED_TEMPLATE := deploy/template.packaged.yml
.DEFAULT_GOAL := help
.PHONY: help fmt e2e infra publish deploy stats
help: ## List available targets
@grep -hE '^[a-zA-Z0-9_-]+:.*?## ' $(MAKEFILE_LIST) | \
awk 'BEGIN{FS=":.*?## "}{printf " \033[36m%-13s\033[0m %s\n", $$1, $$2}'
fmt: ## Format Python (ruff) and Rust (cargo fmt)
@command -v uvx >/dev/null || { echo "uv not installed — see \`make stats\` for a hint"; exit 1; }
uvx ruff format deploy/lambda/
cargo fmt
e2e: ## Build the site, then check its internal and external links (site/e2e)
cargo run -- build
cargo test -p e2e
infra: ## Deploy/update the CloudFormation stack (also packages Lambda code)
@aws s3api head-bucket --bucket $(ARTIFACTS_BUCKET) --region $(REGION) 2>/dev/null \
|| aws s3api create-bucket --bucket $(ARTIFACTS_BUCKET) --region $(REGION) \
$$(test "$(REGION)" = us-east-1 || echo --create-bucket-configuration LocationConstraint=$(REGION)) \
>/dev/null
aws cloudformation package \
--template-file $(TEMPLATE) \
--s3-bucket $(ARTIFACTS_BUCKET) \
--output-template-file $(PACKAGED_TEMPLATE) \
--region $(REGION)
aws cloudformation deploy \
--template-file $(PACKAGED_TEMPLATE) \
--stack-name $(STACK) \
--parameter-overrides $$(sed -nE -e 's/[[:space:]]*\r?$$//' -e 's/^([A-Za-z_][A-Za-z0-9_]*):[[:space:]]+(.+)$$/\1=\2/p' $(PARAMS)) \
--capabilities CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND \
--region $(REGION)
publish: ## Build the site with tklon, sync to S3 with cache headers, invalidate HTML
cargo run --release -- build
@bucket=$$(aws cloudformation describe-stack-resource --stack-name $(STACK) \
--logical-resource-id WebsiteStaticAssetsBucket \
--query 'StackResourceDetail.PhysicalResourceId' --output text --region $(REGION)); \
dist=$$(aws cloudformation describe-stack-resource --stack-name $(STACK) \
--logical-resource-id CloudfrontDistribution \
--query 'StackResourceDetail.PhysicalResourceId' --output text --region $(REGION)); \
echo "→ syncing hashed/immutable assets to s3://$$bucket"; \
aws s3 sync build/ "s3://$$bucket" --delete \
--exclude 'media/*' --exclude 'masters/*' \
--exclude '*.html' --exclude '*.xml' --exclude '*.txt' \
--cache-control 'public,max-age=31536000,immutable'; \
echo "→ syncing HTML / feeds (short TTL with stale-while-revalidate)"; \
aws s3 sync build/ "s3://$$bucket" --delete --exclude '*' \
--include '*.html' --include '*.xml' --include '*.txt' \
--cache-control 'public,max-age=60,s-maxage=300,stale-while-revalidate=86400'; \
echo "→ invalidating $$dist"; \
aws cloudfront create-invalidation --distribution-id "$$dist" \
--paths '/' '/index.html' '/feed.xml' '/*.html'
deploy: infra publish ## Full deploy: stack update, then content
stats: ## Print access-log report. Override window: WINDOW=12w (default 7d). Units: Nd/Nw/Nmo/Ny/all
@command -v uv >/dev/null || { echo "uv not installed — run \`brew install uv\` (or see https://docs.astral.sh/uv/getting-started/installation/)"; exit 1; }
@LOGS_BUCKET=$$(aws cloudformation describe-stack-resource --stack-name $(STACK) \
--logical-resource-id WebsiteLogsBucket \
--query 'StackResourceDetail.PhysicalResourceId' --output text --region $(REGION)) \
STATS_BUCKET=$$(aws cloudformation describe-stack-resource --stack-name $(STACK) \
--logical-resource-id WebsiteStatsBucket \
--query 'StackResourceDetail.PhysicalResourceId' --output text --region $(REGION)) \
AWS_DEFAULT_REGION=$(REGION) \
uv run deploy/lambda/stats_report.py --local --window $(or $(WINDOW),7d)