diff --git a/Makefile b/Makefile index 3662e5fa..94121b83 100644 --- a/Makefile +++ b/Makefile @@ -1,42 +1,57 @@ -GOPATH=$(shell go env GOPATH) -VERSION=$(shell make -s version) -PYTHON?=python3 -BINPATH?=$(GOPATH)/bin -GOLANGCI_LINT_VERSION=v1.64.5 # version supporting go 1.24 -COVERAGE_DIR?=$(shell mktemp -d) -GOOS=$(shell go env GOHOSTOS) -GOARCH=$(shell go env GOHOSTARCH) +# Modern Makefile for aptly with improved tooling and practices -# Unit Tests and some sysmte tests rely on expired certificates, turn back the time -export TEST_FAKETIME := 2025-01-02 03:04:05 +SHELL := /bin/bash +.DEFAULT_GOAL := help +.PHONY: help -# export CAPUTRE=1 for regenrating test gold files -ifeq ($(CAPTURE),1) -CAPTURE_ARG := --capture -endif +# Version and build info +VERSION := $(shell make -s version) +BUILD_DATE := $(shell date -u +"%Y-%m-%dT%H:%M:%SZ") +GIT_COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown") +LDFLAGS := -X main.Version=$(VERSION) -X main.BuildDate=$(BUILD_DATE) -X main.GitCommit=$(GIT_COMMIT) -help: ## Print this help - @grep -E '^[a-zA-Z][a-zA-Z0-9_-]*:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' +# Go parameters +GOCMD := go +GOBUILD := $(GOCMD) build +GOTEST := $(GOCMD) test +GOGET := $(GOCMD) get +GOMOD := $(GOCMD) mod +GOFMT := gofmt +GOPATH := $(shell go env GOPATH) +BINPATH := $(GOPATH)/bin +GOOS := $(shell go env GOHOSTOS) +GOARCH := $(shell go env GOHOSTARCH) -prepare: ## Install go module dependencies - # Prepare go modules - go mod verify - go mod tidy -v - # Generate VERSION file - go generate +# Tool versions +GOLANGCI_VERSION := v1.64.5 +AIR_VERSION := v1.52.3 +SWAG_VERSION := v1.16.4 +GOVULNCHECK_VERSION := latest -releasetype: # Print release type: ci (on any branch/commit), release (on a tag) - @reltype=ci ; \ - gitbranch=`git rev-parse --abbrev-ref HEAD` ; \ - if [ "$$gitbranch" = "HEAD" ] && [ "$$FORCE_CI" != "true" ]; then \ - gittag=`git describe --tags --exact-match 2>/dev/null` ;\ - if echo "$$gittag" | grep -q '^v[0-9]'; then \ - reltype=release ; \ - fi ; \ - fi ; \ - echo $$reltype +# Build parameters +BINARY_NAME := aptly +BUILD_DIR := build +COVERAGE_DIR := coverage +COVERAGE_FILE := $(COVERAGE_DIR)/coverage.out -version: ## Print aptly version +# Docker parameters +DOCKER_IMAGE := aptly/aptly +DOCKER_TAG := $(VERSION) + +# Colors for output +COLOR_RESET := \033[0m +COLOR_BOLD := \033[1m +COLOR_GREEN := \033[32m +COLOR_YELLOW := \033[33m +COLOR_RED := \033[31m +COLOR_BLUE := \033[34m + +##@ General + +help: ## Display this help + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +version: ## Show version @ci="" ; \ if [ "`make -s releasetype`" = "ci" ]; then \ ci=`TZ=UTC git show -s --format='+%cd.%h' --date=format-local:'%Y%m%d%H%M%S'`; \ @@ -47,183 +62,233 @@ version: ## Print aptly version echo `grep ^aptly -m1 debian/changelog | sed 's/.*(\([^)]\+\)).*/\1/'`$$ci ; \ fi -swagger-install: - # Install swag - @test -f $(BINPATH)/swag || GOOS= GOARCH= go install github.com/swaggo/swag/cmd/swag@latest - # Generate swagger.conf - cp docs/swagger.conf.tpl docs/swagger.conf - echo "// @version $(VERSION)" >> docs/swagger.conf - -azurite-start: - azurite -l /tmp/aptly-azurite > ~/.azurite.log 2>&1 & \ - echo $$! > ~/.azurite.pid - -azurite-stop: - @kill `cat ~/.azurite.pid` - -swagger: swagger-install - # Generate swagger docs - @PATH=$(BINPATH)/:$(PATH) swag init --parseDependency --parseInternal --markdownFiles docs --generalInfo docs/swagger.conf - -etcd-install: - # Install etcd - test -d /tmp/aptly-etcd || system/t13_etcd/install-etcd.sh - -flake8: ## run flake8 on system test python files - flake8 system/ - -lint: prepare - # Install golangci-lint - @test -f $(BINPATH)/golangci-lint || go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) - # Running lint - @NO_COLOR=true PATH=$(BINPATH)/:$(PATH) golangci-lint run --max-issues-per-linter=0 --max-same-issues=0 - - -build: prepare swagger ## Build aptly - go build -o build/aptly - -install: - @echo "\e[33m\e[1mBuilding aptly ...\e[0m" - # go generate - @go generate - # go install -v - @out=`mktemp`; if ! go install -v > $$out 2>&1; then cat $$out; rm -f $$out; echo "\nBuild failed\n"; exit 1; else rm -f $$out; fi - -test: prepare swagger etcd-install ## Run unit tests (add TEST=regex to specify which tests to run) - @echo "\e[33m\e[1mStarting etcd ...\e[0m" - @mkdir -p /tmp/aptly-etcd-data; system/t13_etcd/start-etcd.sh > /tmp/aptly-etcd-data/etcd.log 2>&1 & - @echo "\e[33m\e[1mRunning go test ...\e[0m" - faketime "$(TEST_FAKETIME)" go test -v ./... -gocheck.v=true -check.f "$(TEST)" -coverprofile=unit.out; echo $$? > .unit-test.ret - @echo "\e[33m\e[1mStopping etcd ...\e[0m" - @pid=`cat /tmp/etcd.pid`; kill $$pid - @rm -f /tmp/aptly-etcd-data/etcd.log - @ret=`cat .unit-test.ret`; if [ "$$ret" = "0" ]; then echo "\n\e[32m\e[1mUnit Tests SUCCESSFUL\e[0m"; else echo "\n\e[31m\e[1mUnit Tests FAILED\e[0m"; fi; rm -f .unit-test.ret; exit $$ret - -system-test: prepare swagger etcd-install ## Run system tests - # build coverage binary - go test -v -coverpkg="./..." -c -tags testruncli - # Download fixture-db, fixture-pool, etcd.db - if [ ! -e ~/aptly-fixture-db ]; then git clone https://github.com/aptly-dev/aptly-fixture-db.git ~/aptly-fixture-db/; fi - if [ ! -e ~/aptly-fixture-pool ]; then git clone https://github.com/aptly-dev/aptly-fixture-pool.git ~/aptly-fixture-pool/; fi - test -f ~/etcd.db || (curl -o ~/etcd.db.xz http://repo.aptly.info/system-tests/etcd.db.xz && xz -d ~/etcd.db.xz) - # Run system tests - PATH=$(BINPATH)/:$(PATH) FORCE_COLOR=1 $(PYTHON) system/run.py --long --coverage-dir $(COVERAGE_DIR) $(CAPTURE_ARG) $(TEST) - -bench: - @echo "\e[33m\e[1mRunning benchmark ...\e[0m" - go test -v ./deb -run=nothing -bench=. -benchmem - -serve: prepare swagger-install ## Run development server (auto recompiling) - test -f $(BINPATH)/air || go install github.com/air-verse/air@v1.52.3 - cp debian/aptly.conf ~/.aptly.conf - sed -i /enable_swagger_endpoint/s/false/true/ ~/.aptly.conf - PATH=$(BINPATH):$$PATH air -build.pre_cmd 'swag init -q --markdownFiles docs --generalInfo docs/swagger.conf' -build.exclude_dir docs,system,debian,pgp/keyrings,pgp/test-bins,completion.d,man,deb/testdata,console,_man,systemd,obj-x86_64-linux-gnu -- api serve -listen 0.0.0.0:3142 - -dpkg: prepare swagger ## Build debian packages - @test -n "$(DEBARCH)" || (echo "please define DEBARCH"; exit 1) - # set debian version - @if [ "`make -s releasetype`" = "ci" ]; then \ - echo CI Build, setting version... ; \ - test ! -f debian/changelog.dpkg-bak || mv debian/changelog.dpkg-bak debian/changelog ; \ - cp debian/changelog debian/changelog.dpkg-bak ; \ - DEBEMAIL="CI " dch -v `make -s version` "CI build" ; \ - fi - # clean - rm -rf obj-i686-linux-gnu obj-arm-linux-gnueabihf obj-aarch64-linux-gnu obj-x86_64-linux-gnu - # Run dpkg-buildpackage - @buildtype="any" ; \ - if [ "$(DEBARCH)" = "amd64" ]; then \ - buildtype="any,all" ; \ +releasetype: # Print release type: ci (on any branch/commit), release (on a tag) + @reltype=ci ; \ + gitbranch=`git rev-parse --abbrev-ref HEAD` ; \ + if [ "$$gitbranch" = "HEAD" ] && [ "$$FORCE_CI" != "true" ]; then \ + gittag=`git describe --tags --exact-match 2>/dev/null` ;\ + if echo "$$gittag" | grep -q '^v[0-9]'; then \ + reltype=release ; \ + fi ; \ fi ; \ - echo "\e[33m\e[1mBuilding: $$buildtype\e[0m" ; \ - cmd="dpkg-buildpackage -us -uc --build=$$buildtype -d --host-arch=$(DEBARCH)" ; \ - echo "$$cmd" ; \ - $$cmd - lintian ../*_$(DEBARCH).changes || true - # cleanup - @test ! -f debian/changelog.dpkg-bak || mv debian/changelog.dpkg-bak debian/changelog; \ - mkdir -p build && mv ../*.deb build/ ; \ - cd build && ls -l *.deb + echo $$reltype -binaries: prepare swagger ## Build binary releases (FreeBSD, macOS, Linux generic) - # build aptly - GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o build/tmp/aptly -ldflags='-extldflags=-static' - # install - @mkdir -p build/tmp/man build/tmp/completion/bash_completion.d build/tmp/completion/zsh/vendor-completions - @cp man/aptly.1 build/tmp/man/ - @cp completion.d/aptly build/tmp/completion/bash_completion.d/ - @cp completion.d/_aptly build/tmp/completion/zsh/vendor-completions/ - @cp README.rst LICENSE AUTHORS build/tmp/ - @gzip -f build/tmp/man/aptly.1 - @path="aptly_$(VERSION)_$(GOOS)_$(GOARCH)"; \ - rm -rf "build/$$path"; \ - mv build/tmp build/"$$path"; \ - rm -rf build/tmp; \ - cd build; \ - zip -r "$$path".zip "$$path" > /dev/null \ - && echo "Built build/$${path}.zip"; \ - rm -rf "$$path" +##@ Development -docker-image: ## Build aptly-dev docker image - @docker build -f system/Dockerfile . -t aptly-dev +prepare: ## Prepare development environment + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Preparing development environment...$(COLOR_RESET)" + $(GOMOD) download + $(GOMOD) verify + $(GOMOD) tidy -v + @go generate ./... -docker-image-no-cache: ## Build aptly-dev docker image (no cache) - @docker build --no-cache -f system/Dockerfile . -t aptly-dev +dev-tools: ## Install development tools + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Installing development tools...$(COLOR_RESET)" + @go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_VERSION) + @go install github.com/air-verse/air@$(AIR_VERSION) + @go install github.com/swaggo/swag/cmd/swag@$(SWAG_VERSION) + @go install golang.org/x/vuln/cmd/govulncheck@$(GOVULNCHECK_VERSION) + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Development tools installed$(COLOR_RESET)" -docker-build: ## Build aptly in docker container - @docker run -it --rm -v ${PWD}:/work/src aptly-dev /work/src/system/docker-wrapper build +##@ Build -docker-shell: ## Run aptly and other commands in docker container - @docker run -it --rm -p 3142:3142 -v ${PWD}:/work/src aptly-dev /work/src/system/docker-wrapper || true +build: prepare swagger ## Build aptly binary + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Building aptly $(VERSION)...$(COLOR_RESET)" + @mkdir -p $(BUILD_DIR) + $(GOBUILD) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME) . + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Build complete: $(BUILD_DIR)/$(BINARY_NAME)$(COLOR_RESET)" -docker-deb: ## Build debian packages in docker container - @docker run -it --rm -v ${PWD}:/work/src aptly-dev /work/src/system/docker-wrapper dpkg DEBARCH=amd64 +build-all: prepare swagger ## Build for all platforms + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Building for all platforms...$(COLOR_RESET)" + @mkdir -p $(BUILD_DIR) + # Linux + GOOS=linux GOARCH=amd64 $(GOBUILD) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-linux-amd64 + GOOS=linux GOARCH=arm64 $(GOBUILD) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64 + # macOS + GOOS=darwin GOARCH=amd64 $(GOBUILD) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-darwin-amd64 + GOOS=darwin GOARCH=arm64 $(GOBUILD) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-darwin-arm64 + # Windows + GOOS=windows GOARCH=amd64 $(GOBUILD) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-windows-amd64.exe + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Multi-platform build complete$(COLOR_RESET)" -docker-unit-test: ## Run unit tests in docker container (add TEST=regex to specify which tests to run) - @docker run -it --rm -v ${PWD}:/work/src aptly-dev /work/src/system/docker-wrapper \ - azurite-start \ - AZURE_STORAGE_ENDPOINT=http://127.0.0.1:10000/devstoreaccount1 \ - AZURE_STORAGE_ACCOUNT=devstoreaccount1 \ - AZURE_STORAGE_ACCESS_KEY="Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==" \ - test TEST=$(TEST) \ - azurite-stop +install: build ## Install aptly to GOPATH/bin + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Installing aptly...$(COLOR_RESET)" + @cp $(BUILD_DIR)/$(BINARY_NAME) $(BINPATH)/ + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Installed to $(BINPATH)/$(BINARY_NAME)$(COLOR_RESET)" -docker-system-test: ## Run system tests in docker container (add TEST=t04_mirror or TEST=UpdateMirror26Test to run only specific tests) - @docker run -it --rm -v ${PWD}:/work/src aptly-dev /work/src/system/docker-wrapper \ - azurite-start \ - AZURE_STORAGE_ENDPOINT=http://127.0.0.1:10000/devstoreaccount1 \ - AZURE_STORAGE_ACCOUNT=devstoreaccount1 \ - AZURE_STORAGE_ACCESS_KEY="Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==" \ - AWS_ACCESS_KEY_ID=$(AWS_ACCESS_KEY_ID) \ - AWS_SECRET_ACCESS_KEY=$(AWS_SECRET_ACCESS_KEY) \ - system-test TEST=$(TEST) \ - azurite-stop +##@ Testing -docker-serve: ## Run development server (auto recompiling) on http://localhost:3142 - @docker run -it --rm -p 3142:3142 -v ${PWD}:/work/src aptly-dev /work/src/system/docker-wrapper serve || true +test: prepare test-unit test-integration ## Run all tests -docker-lint: ## Run golangci-lint in docker container - @docker run -it --rm -v ${PWD}:/work/src aptly-dev /work/src/system/docker-wrapper lint +test-unit: prepare swagger etcd-install ## Run unit tests + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Running unit tests...$(COLOR_RESET)" + @mkdir -p $(COVERAGE_DIR) + $(GOTEST) -v -race -coverprofile=$(COVERAGE_DIR)/unit.out -covermode=atomic ./... + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Unit tests complete$(COLOR_RESET)" -docker-binaries: ## Build binary releases (FreeBSD, macOS, Linux generic) in docker container - @docker run -it --rm -v ${PWD}:/work/src aptly-dev /work/src/system/docker-wrapper binaries +test-integration: prepare swagger etcd-install ## Run integration tests + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Running integration tests...$(COLOR_RESET)" + @mkdir -p $(COVERAGE_DIR) + # Download fixtures if needed + @if [ ! -e ~/aptly-fixture-db ]; then \ + git clone https://github.com/aptly-dev/aptly-fixture-db.git ~/aptly-fixture-db/; \ + fi + @if [ ! -e ~/aptly-fixture-pool ]; then \ + git clone https://github.com/aptly-dev/aptly-fixture-pool.git ~/aptly-fixture-pool/; \ + fi + # Run system tests + PATH=$(BINPATH):$$PATH python3 system/run.py --coverage-dir $(COVERAGE_DIR) $(TEST) + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Integration tests complete$(COLOR_RESET)" -docker-man: ## Create man page in docker container - @docker run -it --rm -v ${PWD}:/work/src aptly-dev /work/src/system/docker-wrapper man +test-race: ## Run tests with race detector + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Running tests with race detector...$(COLOR_RESET)" + $(GOTEST) -race -short ./... + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Race detection complete$(COLOR_RESET)" -mem.png: mem.dat mem.gp - gnuplot mem.gp - open mem.png +coverage: test ## Generate coverage report + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Generating coverage report...$(COLOR_RESET)" + @mkdir -p $(COVERAGE_DIR) + @go tool cover -html=$(COVERAGE_DIR)/unit.out -o $(COVERAGE_DIR)/coverage.html + @go tool cover -func=$(COVERAGE_DIR)/unit.out + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Coverage report: $(COVERAGE_DIR)/coverage.html$(COLOR_RESET)" -man: ## Create man pages - make -C man +benchmark: ## Run benchmarks + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Running benchmarks...$(COLOR_RESET)" + $(GOTEST) -bench=. -benchmem ./deb ./files ./utils + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Benchmarks complete$(COLOR_RESET)" -clean: ## remove local build and module cache - # Clean all generated and build files - test ! -e .go || find .go/ -type d ! -perm -u=w -exec chmod u+w {} \; - rm -rf .go/ - rm -rf build/ obj-*-linux-gnu* tmp/ - rm -f unit.out aptly.test VERSION docs/docs.go docs/swagger.json docs/swagger.yaml docs/swagger.conf - find system/ -type d -name __pycache__ -exec rm -rf {} \; 2>/dev/null || true +##@ Code Quality -.PHONY: help man prepare swagger version binaries build docker-release docker-system-test docker-unit-test docker-lint docker-build docker-image docker-man docker-shell docker-serve clean releasetype dpkg serve flake8 +lint: dev-tools ## Run linters + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Running linters...$(COLOR_RESET)" + @golangci-lint run --timeout=5m + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Linting complete$(COLOR_RESET)" + +fmt: ## Format code + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Formatting code...$(COLOR_RESET)" + @$(GOFMT) -w -s . + @$(GOMOD) tidy + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Code formatted$(COLOR_RESET)" + +vet: ## Run go vet + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Running go vet...$(COLOR_RESET)" + @go vet ./... + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Vet complete$(COLOR_RESET)" + +security: dev-tools ## Run security checks + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Running security checks...$(COLOR_RESET)" + @govulncheck ./... + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Security check complete$(COLOR_RESET)" + +##@ Dependencies + +deps-update: ## Update dependencies + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Updating dependencies...$(COLOR_RESET)" + @./scripts/update-deps.sh + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Dependencies updated$(COLOR_RESET)" + +deps-check: ## Check for outdated dependencies + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Checking for outdated dependencies...$(COLOR_RESET)" + @go list -u -m all | grep '\[' || echo "All dependencies are up to date!" + +deps-graph: ## Generate dependency graph + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Generating dependency graph...$(COLOR_RESET)" + @go mod graph | grep -v '@' | sort | uniq + +##@ Documentation + +swagger: swagger-install ## Generate Swagger documentation + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Generating Swagger documentation...$(COLOR_RESET)" + @cp docs/swagger.conf.tpl docs/swagger.conf + @echo "// @version $(VERSION)" >> docs/swagger.conf + @swag init --parseDependency --parseInternal --markdownFiles docs --generalInfo docs/swagger.conf + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Swagger docs generated$(COLOR_RESET)" + +swagger-install: ## Install swagger tools + @test -f $(BINPATH)/swag || go install github.com/swaggo/swag/cmd/swag@$(SWAG_VERSION) + +docs: swagger ## Generate all documentation + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Documentation generated$(COLOR_RESET)" + +##@ Development Server + +serve: dev-tools prepare ## Run development server with hot reload + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Starting development server...$(COLOR_RESET)" + @cp debian/aptly.conf ~/.aptly.conf || true + @sed -i.bak '/enable_swagger_endpoint/s/false/true/' ~/.aptly.conf || true + @air -build.pre_cmd 'swag init -q --markdownFiles docs --generalInfo docs/swagger.conf' \ + -build.exclude_dir docs,system,debian,pgp/keyrings,pgp/test-bins,completion.d,man,deb/testdata,console,_man,systemd,obj-x86_64-linux-gnu \ + -- api serve -listen 0.0.0.0:3142 + +##@ Docker + +docker-build: ## Build Docker image + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Building Docker image...$(COLOR_RESET)" + docker build -t $(DOCKER_IMAGE):$(DOCKER_TAG) -t $(DOCKER_IMAGE):latest . + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Docker image built: $(DOCKER_IMAGE):$(DOCKER_TAG)$(COLOR_RESET)" + +docker-push: ## Push Docker image + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Pushing Docker image...$(COLOR_RESET)" + docker push $(DOCKER_IMAGE):$(DOCKER_TAG) + docker push $(DOCKER_IMAGE):latest + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Docker image pushed$(COLOR_RESET)" + +##@ Cleanup + +clean: ## Clean build artifacts + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Cleaning build artifacts...$(COLOR_RESET)" + @rm -rf $(BUILD_DIR) $(COVERAGE_DIR) + @rm -f docs/docs.go docs/swagger.json docs/swagger.yaml docs/swagger.conf + @rm -rf obj-* *.out *.test + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Clean complete$(COLOR_RESET)" + +clean-deps: ## Clean dependency cache + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Cleaning dependency cache...$(COLOR_RESET)" + @go clean -modcache + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Dependency cache cleaned$(COLOR_RESET)" + +##@ CI/CD + +ci: prepare lint test security ## Run CI pipeline + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ CI pipeline complete$(COLOR_RESET)" + +release: clean build-all ## Prepare release artifacts + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Preparing release $(VERSION)...$(COLOR_RESET)" + @mkdir -p $(BUILD_DIR)/release + @for file in $(BUILD_DIR)/$(BINARY_NAME)-*; do \ + base=$$(basename $$file); \ + tar -czf $(BUILD_DIR)/release/$$base.tar.gz -C $(BUILD_DIR) $$base; \ + done + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Release artifacts ready in $(BUILD_DIR)/release$(COLOR_RESET)" + +##@ Utilities + +etcd-install: ## Install etcd for testing + @test -d /tmp/aptly-etcd || system/t13_etcd/install-etcd.sh + +etcd-start: ## Start etcd + @mkdir -p /tmp/aptly-etcd-data + @system/t13_etcd/start-etcd.sh > /tmp/aptly-etcd-data/etcd.log 2>&1 & + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ etcd started$(COLOR_RESET)" + +etcd-stop: ## Stop etcd + @kill `cat /tmp/etcd.pid` 2>/dev/null || true + @rm -f /tmp/etcd.pid + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ etcd stopped$(COLOR_RESET)" + +azurite-start: ## Start Azurite (Azure Storage Emulator) for tests + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Starting Azurite...$(COLOR_RESET)" + @azurite -l /tmp/aptly-azurite > ~/.azurite.log 2>&1 & \ + echo $$! > ~/.azurite.pid + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Azurite started (PID: $$(cat ~/.azurite.pid))$(COLOR_RESET)" + +azurite-stop: ## Stop Azurite + @echo -e "$(COLOR_YELLOW)$(COLOR_BOLD)Stopping Azurite...$(COLOR_RESET)" + @-kill `cat ~/.azurite.pid` 2>/dev/null || true + @rm -f ~/.azurite.pid + @echo -e "$(COLOR_GREEN)$(COLOR_BOLD)✓ Azurite stopped$(COLOR_RESET)" + +.PHONY: all build build-all install test test-unit test-integration test-race coverage benchmark \ + lint fmt vet security deps-update deps-check deps-graph docs swagger swagger-install serve \ + docker-build docker-push clean clean-deps ci release prepare dev-tools etcd-install etcd-start etcd-stop \ + azurite-start azurite-stop \ No newline at end of file