diff --git a/.github/workflows/golangci-lint.yaml b/.github/workflows/lint.yaml similarity index 62% rename from .github/workflows/golangci-lint.yaml rename to .github/workflows/lint.yaml index 1342b390..4d890268 100644 --- a/.github/workflows/golangci-lint.yaml +++ b/.github/workflows/lint.yaml @@ -1,15 +1,18 @@ -name: golangci-lint +name: Run linters on: push: branches: - main pull_request: jobs: - golangci-lint: + lint: name: golangci-lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - name: sam-validate + run: | + make sam-validate - name: golangci-lint run: | - make go-lint-all + make go-lint diff --git a/.github/workflows/sam-validate.yaml b/.github/workflows/sam-validate.yaml deleted file mode 100644 index da4c1e4b..00000000 --- a/.github/workflows/sam-validate.yaml +++ /dev/null @@ -1,20 +0,0 @@ -name: Run Validate - -on: - push: - branches: - - main - pull_request: -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: aws-actions/setup-sam@v2 - with: - use-installer: true - - uses: actions/setup-python@v5 - with: - python-version: '3.12' - - run: pip install -r dev-requirements.txt - - run: make sam-validate-all diff --git a/.github/workflows/tests-integration.yaml b/.github/workflows/tests-integration.yaml index ff4bb758..0314606c 100644 --- a/.github/workflows/tests-integration.yaml +++ b/.github/workflows/tests-integration.yaml @@ -1,11 +1,7 @@ -name: Run IAC Integration Tests +name: Run Integration Tests on: - # push: - # branches: - # - main - # release.yaml runs the tests on commits to main - pull_request: + # pull_request: workflow_dispatch: inputs: debug_enabled: @@ -14,8 +10,13 @@ on: required: false default: false workflow_call: - schedule: - - cron: '0 0 * * 1' # Monday at 00:00 UTC + #schedule: + #- cron: '0 0 * * 1' # Monday at 00:00 UTC + +env: + AWS_REGION: us-west-2 + S3_BUCKET_PREFIX: "${{ github.run_id }}-" + SAM_CLI_TELEMETRY: 0 jobs: permission_check: @@ -34,26 +35,29 @@ jobs: echo "can-write=true" >> $GITHUB_OUTPUT fi - prepare_matrix: + discover: needs: [permission_check] if: needs.permission_check.outputs.can-write == 'true' runs-on: ubuntu-latest outputs: - matrix: ${{ steps.find_hcl_files.outputs.matrix }} + tests: ${{ steps.find_hcl_files.outputs.matrix }} steps: - uses: actions/checkout@v4 - name: Setup the test matrix id: find_hcl_files run: | - cd integration && \ - echo "matrix=$(ls tests/*.hcl | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT + echo "matrix=$(ls integration/tests | awk -F. '{print $1}' | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT + package: + needs: [permission_check] + if: needs.permission_check.outputs.can-write == 'true' + runs-on: ubuntu-latest + steps: - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 - with: - go-version-file: 'go.mod' + - name: Fetch tags for versioning + run: git fetch --prune --unshallow --tags - name: DCE Provision uses: observeinc/github-action-dce@1.0.1 @@ -67,17 +71,14 @@ jobs: - name: Create S3 Bucket for Artifacts run: | - if ! aws s3api head-bucket --bucket "${{ github.run_id }}-$AWS_REGION" 2>/dev/null; then - aws s3 mb s3://"${{ github.run_id }}-$AWS_REGION" --region us-west-2 + if ! aws s3api head-bucket --bucket "${{ env.S3_BUCKET_PREFIX }}${{ env.AWS_REGION }}" 2>/dev/null; then + aws s3 mb s3://"${{ env.S3_BUCKET_PREFIX }}${{ env.AWS_REGION }}" --region us-west-2 fi - env: - AWS_REGION: us-west-2 - name: Package SAM Applications - run: make sam-package-all + run: make sam-package env: - AWS_REGION: us-west-2 - S3_BUCKET_PREFIX: ${{ github.run_id }} + MAKEFLAGS: "-j 4" - name: Setup tmate session uses: mxschmitt/action-tmate@v3 @@ -90,15 +91,15 @@ jobs: with: name: repo-and-sam-build path: | - ${{ github.workspace }}/.aws-sam/ + ${{ github.workspace }}/.aws-sam/build/regions test-integration: runs-on: ubuntu-latest - needs: [permission_check, prepare_matrix] + needs: [permission_check, discover, package] if: needs.permission_check.outputs.can-write == 'true' strategy: matrix: - testfile: ${{fromJson(needs.prepare_matrix.outputs.matrix)}} + testfile: ${{fromJson(needs.discover.outputs.tests)}} steps: - name: DCE Use id: dce_setup @@ -114,17 +115,10 @@ jobs: uses: actions/download-artifact@v4 with: name: repo-and-sam-build - path: ${{ github.workspace }}/.aws-sam/ + path: ${{ github.workspace }}/.aws-sam/build/regions - - uses: actions/setup-go@v5 - with: - go-version-file: 'go.mod' - - - name: Integration test for ${{ matrix.testfile }} - run: S3_BUCKET_PREFIX=${S3_BUCKET_PREFIX} TEST_ARGS='-filter=${{ matrix.testfile }} -verbose' make integration-test - env: - AWS_REGION: us-west-2 - S3_BUCKET_PREFIX: ${{ github.run_id }} + - name: Run ${{ matrix.testfile }} integration test + run: TEST_ARGS='-verbose' make test-integration-${{ matrix.testfile }} cleanup: needs: [permission_check, test-integration] diff --git a/.github/workflows/tests-unit.yaml b/.github/workflows/tests-unit.yaml deleted file mode 100644 index 56b9f531..00000000 --- a/.github/workflows/tests-unit.yaml +++ /dev/null @@ -1,26 +0,0 @@ -name: Run Go tests - -on: - push: - tags: - - v* - branches: - - main - pull_request: - -jobs: - test: - strategy: - matrix: - go: [ 1.22.x ] - platform: [ ubuntu-latest ] - runs-on: ${{ matrix.platform }} - steps: - - name: Install Go - uses: actions/setup-go@v5 - with: - go-version: ${{ matrix.go }} - - name: Checkout code - uses: actions/checkout@v4 - - name: Test - run: make go-test diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 56b9f531..2d27b0df 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -1,4 +1,4 @@ -name: Run Go tests +name: Run tests on: push: @@ -9,18 +9,15 @@ on: pull_request: jobs: - test: - strategy: - matrix: - go: [ 1.22.x ] - platform: [ ubuntu-latest ] - runs-on: ${{ matrix.platform }} + go-test: + runs-on: ubuntu-latest steps: - - name: Install Go - uses: actions/setup-go@v5 - with: - go-version: ${{ matrix.go }} - name: Checkout code uses: actions/checkout@v4 - - name: Test + - name: Go unit tests run: make go-test + + integration: + needs: go-test + uses: ./.github/workflows/tests-integration.yaml + secrets: inherit diff --git a/.gitignore b/.gitignore index f70e8b45..f0aca7c1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ .aws-sam/ .*.swp build/ +.go +bin/ .terraform terraform.tfstate diff --git a/.golangci.yaml b/.golangci.yaml deleted file mode 100644 index e1bae8ac..00000000 --- a/.golangci.yaml +++ /dev/null @@ -1,36 +0,0 @@ -run: - timeout: 10m - -linters: - disable-all: true - # Disable specific linter - # https://golangci-lint.run/usage/linters/#disabled-by-default-linters--e--enable - enable: - - asciicheck - - errcheck - - forcetypeassert - - errname - - exportloopref - - gocritic - - godot - - goerr113 - - gofmt - - gofumpt - - goimports - - gosimple - - govet - - ineffassign - - misspell - - nestif - - nilerr - - promlinter - - revive - - staticcheck - - tenv - - testpackage - - thelper - - tparallel - - typecheck - - unused - - whitespace - - wrapcheck diff --git a/Makefile b/Makefile index b63c6ad1..07f19a80 100644 --- a/Makefile +++ b/Makefile @@ -2,183 +2,175 @@ SHELL := /bin/bash .DEFAULT_GOAL := help .ONESHELL: -VERSION ?= unreleased +DBG_MAKEFILE ?= +ifeq ($(DBG_MAKEFILE),1) + $(warning ***** starting Makefile for goal(s) "$(MAKECMDGOALS)") + $(warning ***** $(shell date)) +else + # If we're not debugging the Makefile, don't echo recipes. + MAKEFLAGS += -s +endif +# We don't need make's built-in rules. +MAKEFLAGS += --no-builtin-rules +# Be pedantic about undefined variables. +MAKEFLAGS += --warn-undefined-variables +.SUFFIXES: + +VERSION ?= $(shell git describe --tags --always --dirty) + +-include golang.mk + + + +APPS := $(shell find apps/* -type d -maxdepth 0 -exec basename {} \;) +AWS_REGION ?= us-west-2 +AWS_REGIONS := us-west-2 \ + us-west-1 \ + us-east-2 \ + us-east-1 \ + sa-east-1 \ + eu-west-3 \ + eu-west-2 \ + eu-west-1 \ + eu-north-1 \ + eu-central-1 \ + ca-central-1 \ + ap-southeast-2 \ + ap-southeast-1 \ + ap-south-1 \ + ap-northeast-3 \ + ap-northeast-2 \ + ap-northeast-1 \ + # leave this undefined for the purposes of development -S3_BUCKET_PREFIX ?= -AWS_REGION ?= $(shell aws configure get region) -SAM_BUILD_DIR ?= .aws-sam/build -SAM_CONFIG_FILE ?= $(shell pwd)/samconfig.yaml -SAM_CONFIG_ENV ?= default -BUILD_MAKEFILE_ENV_VARS = .make.env +S3_BUCKET_PREFIX ?= +SAM_BUILD_DIR ?= .aws-sam/build +SAM_CONFIG_FILE ?= $(shell pwd)/samconfig.yaml +SAM_CONFIG_ENV ?= default +TF_TESTS ?= $(shell ls integration/tests | awk -F. '{print $$1}') +TF_TEST_DEBUG ?= 0 +TF_TEST_ARGS ?= + +.PHONY: clean +clean: # @HELP removes built binaries and temporary files +clean: bin-clean + rm -rf $(SAM_BUILD_DIR) -DEBUG ?= 0 +SAM_BUILD_TEMPLATES = $(foreach app,$(APPS), $(SAM_BUILD_DIR)/apps/$(app)/template.yaml) -define check_var - @[[ -n "$($1)" ]] || (echo >&2 "The environment variable '$1' is not set." && exit 2) -endef +$(foreach template,$(SAM_BUILD_TEMPLATE),$(eval \ + $(template): apps/$(call get_app, $(template))/template.yaml \ +)) -SUBDIR = $(shell ls apps) +$(SAM_BUILD_TEMPLATES): go-build bin/Makefile + sam build \ + -p \ + -beta-features \ + --template-file $(patsubst $(SAM_BUILD_DIR)/%,%,$@) \ + --build-dir $(patsubst %template.yaml,%,$@) \ + --config-file $(SAM_CONFIG_FILE) \ + --config-env $(SAM_CONFIG_ENV) -.PHONY: help go-lint go-lint-all go-test integration-test debug sam-validate sam-validate-all sam-build-all sam-build sam-publish sam-package-all sam-package release-all release sam-publish-all build-App build-Forwarder build-Subscriber clean-aws-sam +SAM_PACKAGE_TARGETS = $(foreach app,$(APPS),sam-package-$(app)) -clean-aws-sam: - rm -rf $(SAM_BUILD_DIR) +.PHONY: $(SAM_PACKAGE_TARGETS) +# map each SAM_PACKAGE_TARGET to the corresponding SAM_PACKAGE_TEMPLATE for our current region +$(foreach target,$(SAM_PACKAGE_TARGETS),$(eval \ + $(target): $(SAM_BUILD_DIR)/regions/$(AWS_REGION)/$(lastword $(subst -, , $(target))).yaml \ +)) -## help: Displays this help message listing all targets -help: - @echo "Usage: make [target]" - @sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /' - -## go-lint: Runs Go linter for a specified directory, set with PACKAGE variable -go-lint: - $(call check_var,PACKAGE) - docker run --rm -v "`pwd`:/workspace:cached" -w "/workspace/$(PACKAGE)" golangci/golangci-lint:latest golangci-lint run - -## go-lint-all: Executes Go linter for all Go packages in the project -go-lint-all: - docker run --rm -v "`pwd`:/workspace:cached" -w "/workspace/." golangci/golangci-lint:latest golangci-lint run - -## go-test: Runs Go tests across all packages -go-test: - go build ./... - go test -v -race ./... - -## integration-test: Executes integration tests, with optional debugging if DEBUG=1 -integration-test: - cd integration && terraform init && \ - if [ "$(DEBUG)" = "1" ]; then \ - CHECK_DEBUG_FILE=debug.sh terraform test $(TEST_ARGS); \ - else \ - terraform test $(TEST_ARGS); \ - fi +define get_region +$(lastword $(subst /, ,$(basename $(dir $(1))))) +endef -## sam-validate: Validates a specific CloudFormation template specified by APP variable -sam-validate: - $(call check_var,APP) - yamllint apps/$(APP)/template.yaml && \ - sam validate \ - --template apps/$(APP)/template.yaml \ - --config-file $(SAM_CONFIG_FILE) \ - --config-env $(SAM_CONFIG_ENV) +define get_app +$(subst .yaml,,$(lastword $(subst /, ,$(1)))) +endef -## sam-validate-all: Validates all CloudFormation templates in the project -sam-validate-all: - @ for dir in $(SUBDIR); do \ - APP=$$dir $(MAKE) sam-validate || exit 1; \ - done - -## sam-build-all: Builds assets for all SAM applications across specified regions -sam-build-all: - @ for app in $(SUBDIR); do \ - for region in $(REGIONS); do \ - APP=$$app AWS_REGION=$$region $(MAKE) sam-build || exit 1; \ - done \ - done - -## sam-build: Builds assets for a specific SAM application, specified by APP variable -sam-build: - $(call check_var,APP) - echo "VERSION=${VERSION}" > ${BUILD_MAKEFILE_ENV_VARS} - sam build \ - --template-file apps/$(APP)/template.yaml \ - --build-dir $(SAM_BUILD_DIR)/$(APP)/$(AWS_REGION) \ - --config-file $(SAM_CONFIG_FILE) \ - --config-env $(SAM_CONFIG_ENV) +SAM_PACKAGE_DIRS = $(foreach region, $(AWS_REGIONS), $(SAM_BUILD_DIR)/regions/$(region)) +SAM_PACKAGE_TEMPLATES = $(foreach dir,$(SAM_PACKAGE_DIRS), $(foreach app,$(APPS),$(dir)/$(app).yaml)) -## sam-publish: Publishes a specific serverless repository application, after packaging -sam-publish: sam-package - sam publish \ - --template-file $(SAM_BUILD_DIR)/$(APP)/$(AWS_REGION)/packaged.yaml \ - --region $(AWS_REGION) \ - --config-file $(SAM_CONFIG_FILE) \ - --config-env $(SAM_CONFIG_ENV) +$(foreach template,$(SAM_PACKAGE_TEMPLATES),$(eval \ + $(template): $(SAM_BUILD_DIR)/apps/$(call get_app, $(template))/template.yaml \ +)) + +$(SAM_PACKAGE_DIRS): + mkdir -p $@ -## sam-package-all: Packages and pushes all CloudFormation templates to S3 -sam-package-all: - @ for dir in $(SUBDIR); do \ - APP=$$dir $(MAKE) sam-package || exit 1; \ - done - -## sam-package: Packages a specific CloudFormation template and pushes assets to S3, specified by APP variable -sam-package: sam-build - $(call check_var,APP) - $(call check_var,VERSION) - echo "Packaging for app: $(APP) in region: $(AWS_REGION)" +$(SAM_PACKAGE_TEMPLATES): | $(SAM_PACKAGE_DIRS) ifeq ($(S3_BUCKET_PREFIX),) sam package \ - --template-file $(SAM_BUILD_DIR)/$(APP)/$(AWS_REGION)/template.yaml \ - --output-template-file $(SAM_BUILD_DIR)/$(APP)/$(AWS_REGION)/packaged.yaml \ - --region $(AWS_REGION) \ + --template-file $(SAM_BUILD_DIR)/apps/$(call get_app, $@)/template.yaml \ + --output-template-file $@ \ + --region $(call get_region, $@) \ --resolve-s3 \ + --s3-prefix aws-sam-apps/$(VERSION) \ + --no-progressbar \ --config-file $(SAM_CONFIG_FILE) \ --config-env $(SAM_CONFIG_ENV) else sam package \ - --template-file $(SAM_BUILD_DIR)/$(APP)/$(AWS_REGION)/template.yaml \ - --output-template-file $(SAM_BUILD_DIR)/$(APP)/$(AWS_REGION)/packaged.yaml \ - --region $(AWS_REGION) \ - --s3-bucket $(S3_BUCKET_PREFIX)-$(AWS_REGION) \ - --s3-prefix apps/$(APP)/$(VERSION) \ + --template-file apps/$(call get_app, $@)/template.yaml \ + --output-template-file $@ \ + --region $(call get_region, $@) \ + --s3-bucket "$(S3_BUCKET_PREFIX)$(call get_region, $@)" \ + --s3-prefix aws-sam-apps/$(VERSION) \ + --no-progressbar \ --config-file $(SAM_CONFIG_FILE) \ --config-env $(SAM_CONFIG_ENV) endif -## release-all: Releases all applications, ensuring S3_BUCKET_PREFIX is set -release-all: -ifeq ($(S3_BUCKET_PREFIX),) - $(error S3_BUCKET_PREFIX is empty. Cannot proceed with release-all.) -endif - for dir in $(SUBDIR); do \ - APP=$$dir $(MAKE) release || exit 1; \ - done +SAM_VALIDATE_TARGETS = $(foreach app,$(APPS),sam-validate-$(app)) -## release: Packages, uploads, and sets ACL for a specific app, ensuring S3_BUCKET_PREFIX is set, specified by APP variable -release: -ifeq ($(S3_BUCKET_PREFIX),) - $(error S3_BUCKET_PREFIX is empty. Cannot proceed with release.) -endif - $(MAKE) sam-package - @echo "Resetting assets to be public readable" - aws s3 cp --acl public-read --recursive s3://$(S3_BUCKET_PREFIX)-$(AWS_REGION)/apps/$(APP)/$(VERSION)/ s3://$(S3_BUCKET_PREFIX)-$(AWS_REGION)/apps/$(APP)/$(VERSION)/ - @echo "Copying stack definition" - aws s3 cp --acl public-read $(SAM_BUILD_DIR)/$(APP)/$(AWS_REGION)/packaged.yaml s3://$(S3_BUCKET_PREFIX)-$(AWS_REGION)/apps/$(APP)/$(VERSION)/ -ifeq ($(TAG),) -else - aws s3 cp --acl public-read $(SAM_BUILD_DIR)/$(APP)/$(AWS_REGION)/packaged.yaml s3://$(S3_BUCKET_PREFIX)-$(AWS_REGION)/apps/$(APP)/$(TAG)/ -endif +.PHONY: $(SAM_VALIDATE_TARGETS) +$(SAM_VALIDATE_TARGETS): + yamllint apps/$(lastword $(subst -, ,$@))/template.yaml && \ + sam validate \ + --template apps/$(lastword $(subst -, ,$@))/template.yaml \ + --config-file $(SAM_CONFIG_FILE) \ + --config-env $(SAM_CONFIG_ENV) + +TEST_INTEGRATION_TARGETS = $(foreach test,$(TF_TESTS),test-integration-$(test)) -## sam-publish-all: Publishes all serverless applications -sam-publish-all: - for dir in $(SUBDIR); do - APP=$$dir $(MAKE) sam-publish || exit 1; - done - -build-App: - $(call check_var,APP) - $(call check_var,ARTIFACTS_DIR) - GOARCH=arm64 GOOS=linux go build -tags lambda.norpc -ldflags "-X $(shell go list -m)/version.Version=${VERSION}" -o ./bootstrap cmd/$(APP)/main.go - cp ./bootstrap $(ARTIFACTS_DIR)/. - -build-Forwarder: - APP=forwarder $(MAKE) build-App - -build-Subscriber: - APP=subscriber $(MAKE) build-App - -## parameters: generate doc table for cloudformation parameters -parameters: - $(call check_var,APP) - @echo "| Parameter | Type | Description |" - @echo "|-----------------|---------|-------------|" - @python3 -c 'import sys, yaml, json; y=yaml.safe_load(sys.stdin.read()); print(json.dumps(y))' < $(SAM_BUILD_DIR)/$(APP)/$(AWS_REGION)/template.yaml | jq -r '.Parameters | to_entries[] | "| \(if .value.Default then "" else "**" end)`\(.key)`\(if .value.Default then "" else "**" end) | \(.value.Type) | \(.value.Description | gsub("[\\n\\t]"; " ")) |"' - -## static-validate: validate any static assets -static-validate: - @ yamllint --no-warnings static/ - -## static-upload: upload static assets -static-upload: static-validate - $(call check_var,S3_BUCKET_PREFIX) - aws s3 sync static s3://$(S3_BUCKET_PREFIX)/ --acl public-read --metadata Version=$(VERSION) - -.PHONY: help go-lint go-lint-all go-test sam-validate sam-validate-all sam-build sam-package sam-publish sam-package-all sam-publish-all build-App build-Forwarder +test-init: + terraform -chdir=integration init + +.PHONY: $(TEST_INTEGRATION_TARGETS) +$(TEST_INTEGRATION_TARGETS): test-init + if [ "$(TF_TEST_DEBUG)" = "1" ]; then \ + CHECK_DEBUG_FILE=debug.sh terraform -chdir=integration test -filter=tests/$(lastword $(subst -, ,$@)).tftest.hcl $(TF_TEST_ARGS); \ + else \ + terraform -chdir=integration test -filter=tests/$(lastword $(subst -, ,$@)).tftest.hcl $(TF_TEST_ARGS); \ + fi + +.PHONY: release +release: $(SAM_PACKAGE_TEMPLATES) + +.PHONY: sam-package +sam-package: # @HELP package all SAM templates. For specific app append name (e.g sam-package-forwarder) +sam-package: $(SAM_PACKAGE_TARGETS) + +.PHONY: sam-validate +sam-validate: # @HELP validate all SAM templates. For specific app append name (e.g sam-validate-logwriter) +sam-validate: $(SAM_VALIDATE_TARGETS) + +.PHONY: test-integration +test-integration: # @HELP run all integration tests. For specific test append name (e.g test-integration-stack) +test-integration: $(TEST_INTEGRATION_TARGETS) + + +help: # @HELP displays this message +help: + echo "VARIABLES:" + echo " APPS = $(APPS)" + echo " AWS_REGION = $(AWS_REGION)" + echo " BINS = $(BINS)" + echo " TF_TESTS = $(TF_TESTS)" + echo " VERSION = $(VERSION)" + echo + echo "TARGETS:" + grep -E '^.*: *# *@HELP' $(MAKEFILE_LIST) \ + | awk ' \ + BEGIN {FS = ": *# *@HELP"}; \ + { printf " %-30s %s\n", $$1, $$2 }; \ + ' diff --git a/apps/forwarder/template.yaml b/apps/forwarder/template.yaml index 2ef7ba07..cda06be3 100644 --- a/apps/forwarder/template.yaml +++ b/apps/forwarder/template.yaml @@ -388,7 +388,7 @@ Resources: - !Ref AWS::StackName - !Ref NameOverride Role: !GetAtt Role.Arn - CodeUri: ../.. + CodeUri: ../../bin/ Handler: bootstrap Runtime: provided.al2 MemorySize: !If diff --git a/apps/logwriter/template.yaml b/apps/logwriter/template.yaml index a97fb248..cecf578b 100644 --- a/apps/logwriter/template.yaml +++ b/apps/logwriter/template.yaml @@ -422,7 +422,7 @@ Resources: - !Ref AWS::StackName - !Ref NameOverride Role: !GetAtt SubscriberRole.Arn - CodeUri: ../.. + CodeUri: ../../bin/ Handler: bootstrap Runtime: provided.al2 MemorySize: !If diff --git a/golang.mk b/golang.mk new file mode 100644 index 00000000..95f71cea --- /dev/null +++ b/golang.mk @@ -0,0 +1,112 @@ +BINS := forwarder subscriber + +GO_BUILD_IMAGE ?= golang:1.22-alpine + +OS := $(if $(GOOS),$(GOOS),linux) +ARCH := $(if $(GOARCH),$(GOARCH),arm64) + +# Which Go modules mode to use ("mod" or "vendor") +MOD ?= vendor + +# Satisfy --warn-undefined-variables. +GOFLAGS ?= + +# The following structure defeats Go's (intentional) behavior to always touch +# result files, even if they have not changed. This will still run `go` but +# will not trigger further work if nothing has actually changed. +GO_OUTBINS = $(foreach bin,$(BINS),bin/$(OS)_$(ARCH)/$(bin)) + +go-build: $(GO_OUTBINS) + echo + +# Directories that we need created to build/test. +GO_BUILD_DIRS := bin/$(OS)_$(ARCH) \ + .go/bin/$(OS)_$(ARCH) \ + .go/cache \ + .go/pkg + +$(GO_BUILD_DIRS): + mkdir -p $@ + +# Each outbin target is just a facade for the respective stampfile target. +# This `eval` establishes the dependencies for each. +$(foreach outbin,$(GO_OUTBINS),$(eval \ + $(outbin): .go/$(outbin).stamp \ +)) + +# This is the target definition for all outbins. +$(GO_OUTBINS): + true + +# Each stampfile target can reference an $(OUTBIN) variable. +$(foreach outbin,$(GO_OUTBINS),$(eval $(strip \ + .go/$(outbin).stamp: OUTBIN = $(outbin) \ +))) + +# This is the target definition for all stampfiles. +# This will build the binary under ./.go and update the real binary iff needed. +STAMPS = $(foreach outbin,$(GO_OUTBINS),.go/$(outbin).stamp) +.PHONY: $(STAMPS) +$(STAMPS): go-build-bin + echo -ne "binary: $(OUTBIN) " + if ! cmp -s .go/$(OUTBIN) $(OUTBIN); then \ + mv .go/$(OUTBIN) $(OUTBIN); \ + date >$@; \ + echo; \ + else \ + echo "(cached)"; \ + fi + +# This runs the actual `go build` which updates all binaries. +go-build-bin: | $(GO_BUILD_DIRS) + echo "# building $(VERSION) for $(OS)/$(ARCH)" + docker run \ + -i \ + --rm \ + -u $$(id -u):$$(id -g) \ + -v $$(pwd):/src \ + -w /src \ + -v $$(pwd)/.go/bin/$(OS)_$(ARCH):/go/bin/$(OS)_$(ARCH) \ + -v $$(pwd)/.go/cache:/.cache \ + -v $$(pwd)/.go/pkg:/go/pkg \ + --env GOARCH=$(ARCH) \ + --env GOOS=$(OS) \ + $(GO_BUILD_IMAGE) \ + /bin/sh -c " \ + go install \ + -installsuffix \"static\" \ + -ldflags \"-X $$(go list -m)/pkg/version.Version=${VERSION}\" \ + ./... \ + " + +bin/Makefile: $(GO_BUILD_DIRS) + cp lambda.mk $@ + +bin-clean: + test -d .go && chmod -R u+w .go || true + rm -rf .go bin + +go-test: | $(GO_BUILD_DIRS) + docker run \ + -i \ + --rm \ + -u $$(id -u):$$(id -g) \ + -v $$(pwd):/src \ + -w /src \ + -v $$(pwd)/.go/bin/$(OS)_$(ARCH):/go/bin \ + -v $$(pwd)/.go/bin/$(OS)_$(ARCH):/go/bin/$(OS)_$(ARCH) \ + -v $$(pwd)/.go/cache:/.cache \ + -v $$(pwd)/.go/pkg:/go/pkg \ + $(GO_BUILD_IMAGE) \ + /bin/sh -c " \ + ARCH=$(ARCH) \ + OS=$(OS) \ + VERSION=$(VERSION) \ + MOD=$(MOD) \ + GOFLAGS=$(GOFLAGS) \ + go test -installsuffix "static" ./... \ + " + +go-lint: # @HELP lint golang workspace +go-lint: + docker run --rm -v "$$(pwd):/workspace:cached" -w "/workspace/." golangci/golangci-lint:latest golangci-lint run --timeout 3m && echo "lint passed" diff --git a/integration/main.tf b/integration/main.tf index 853827c9..5bb5bb7f 100644 --- a/integration/main.tf +++ b/integration/main.tf @@ -2,7 +2,7 @@ data "aws_region" "current" {} resource "aws_cloudformation_stack" "this" { name = var.setup.stack_name - template_body = file("../.aws-sam/build/${var.app}/${data.aws_region.current.name}/packaged.yaml") + template_body = file("../.aws-sam/build/regions/${data.aws_region.current.name}/${var.app}.yaml") parameters = var.parameters capabilities = var.capabilities iam_role_arn = var.install_policy_json == null ? null : aws_iam_role.this[0].arn diff --git a/lambda.mk b/lambda.mk new file mode 100644 index 00000000..e844f176 --- /dev/null +++ b/lambda.mk @@ -0,0 +1,5 @@ +strip_and_lowercase = $(shell echo $(1) | sed 's/^build-//' | tr '[:upper:]' '[:lower:]') + +build-%: + cp linux_arm64/$(call strip_and_lowercase,$@) $(ARTIFACTS_DIR)/bootstrap + diff --git a/samconfig.yaml b/samconfig.yaml index eb0dc8ca..afed3c40 100644 --- a/samconfig.yaml +++ b/samconfig.yaml @@ -3,8 +3,8 @@ version: 0.1 default: build: parameters: - debug: true - cached: true + debug: false + cached: false # Makefile build doesn't seem to support this parallel: true validate: parameters: