mirror of
https://github.com/GlueOps/autoglue.git
synced 2026-02-13 04:40:05 +01:00
fix: refactor labels to use common entries between model and dto
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -137,3 +137,4 @@ notes.txt
|
|||||||
|
|
||||||
.terraform
|
.terraform
|
||||||
.terraform.lock*
|
.terraform.lock*
|
||||||
|
terraform.tfstate*
|
||||||
297
Makefile
297
Makefile
@@ -1,3 +1,13 @@
|
|||||||
|
# ========= Makefile (optimized + DRY + annotated) =========
|
||||||
|
|
||||||
|
# --- strict shell & make behavior ---
|
||||||
|
SHELL := /usr/bin/env bash
|
||||||
|
.SHELLFLAGS := -eu -o pipefail -c
|
||||||
|
|
||||||
|
.DELETE_ON_ERROR:
|
||||||
|
MAKEFLAGS += --warn-undefined-variables
|
||||||
|
.ONESHELL:
|
||||||
|
|
||||||
# --- variables ---
|
# --- variables ---
|
||||||
GOCMD ?= go
|
GOCMD ?= go
|
||||||
GOINSTALL := $(GOCMD) install
|
GOINSTALL := $(GOCMD) install
|
||||||
@@ -38,10 +48,26 @@ SWAG := $(shell command -v swag 2>/dev/null)
|
|||||||
GMU := $(shell command -v go-mod-upgrade 2>/dev/null)
|
GMU := $(shell command -v go-mod-upgrade 2>/dev/null)
|
||||||
YARN := $(shell command -v yarn 2>/dev/null)
|
YARN := $(shell command -v yarn 2>/dev/null)
|
||||||
NPM := $(shell command -v npm 2>/dev/null)
|
NPM := $(shell command -v npm 2>/dev/null)
|
||||||
OGC := $(shell command -v openapi-generator-cli 2>/dev/null || command -v openapi-generator 2>/dev/null)
|
|
||||||
BROTLI := $(shell command -v brotli 2>/dev/null)
|
BROTLI := $(shell command -v brotli 2>/dev/null)
|
||||||
GZIP := $(shell command -v gzip 2>/dev/null)
|
GZIP := $(shell command -v gzip 2>/dev/null)
|
||||||
.DEFAULT_GOAL := build
|
|
||||||
|
# OpenAPI Generator wrapper (npm) and *core* version pin
|
||||||
|
OGC_WRAPPER ?= @openapitools/openapi-generator-cli@latest
|
||||||
|
OPENAPI_GENERATOR_VERSION ?= 7.17.0
|
||||||
|
OGC_BIN := npx -y $(OGC_WRAPPER)
|
||||||
|
|
||||||
|
# Cache the core generator jar (faster CI/local)
|
||||||
|
export OPENAPI_GENERATOR_CLI_CACHE_DIR ?= $(HOME)/.openapi-generator
|
||||||
|
|
||||||
|
# Toggle alias-as-model (can trigger name collisions in some specs)
|
||||||
|
ALIAS_AS_MODEL ?= true
|
||||||
|
ALIAS_FLAG := $(if $(filter true,$(ALIAS_AS_MODEL)),--generate-alias-as-model,)
|
||||||
|
|
||||||
|
# Post-process generated Go with gofmt (OpenAPI Generator honors this env var)
|
||||||
|
export GO_POST_PROCESS_FILE := gofmt -w
|
||||||
|
|
||||||
|
# Default goal
|
||||||
|
.DEFAULT_GOAL := help
|
||||||
|
|
||||||
# --- version metadata (ldflags) ---
|
# --- version metadata (ldflags) ---
|
||||||
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
|
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
|
||||||
@@ -54,26 +80,74 @@ LDFLAGS := -X '$(MODULE_PATH)/internal/version.Version=$(VERSION)' \
|
|||||||
-X '$(MODULE_PATH)/internal/version.Date=$(DATE)' \
|
-X '$(MODULE_PATH)/internal/version.Date=$(DATE)' \
|
||||||
-X '$(MODULE_PATH)/internal/version.BuiltBy=$(BUILT_BY)'
|
-X '$(MODULE_PATH)/internal/version.BuiltBy=$(BUILT_BY)'
|
||||||
|
|
||||||
|
# --- whitespace trimming helper ---
|
||||||
|
trim = $(strip $1)
|
||||||
|
|
||||||
|
# sanitized copies (use these everywhere in recipes)
|
||||||
|
SDK_OUTDIR_CLEAN := $(call trim,$(SDK_OUTDIR))
|
||||||
|
SDK_TS_DIR_CLEAN := $(call trim,$(SDK_TS_DIR))
|
||||||
|
SDK_TS_UI_DIR_CLEAN := $(call trim,$(SDK_TS_UI_DIR))
|
||||||
|
GIT_HOST_CLEAN := $(call trim,$(GIT_HOST))
|
||||||
|
GIT_USER_CLEAN := $(call trim,$(GIT_USER))
|
||||||
|
SDK_REPO_CLEAN := $(call trim,$(SDK_REPO))
|
||||||
|
SDK_PKG_CLEAN := $(call trim,$(SDK_PKG))
|
||||||
|
|
||||||
# --- phony targets ---
|
# --- phony targets ---
|
||||||
.PHONY: all prepare ui-install ui-build ui swagger build clean fmt vet tidy upgrade \
|
.PHONY: all prepare ui-install ui-build ui swagger build clean fmt vet tidy upgrade \
|
||||||
sdk sdk-go sdk-ts sdk-ts-ui sdk-all worksync wire-sdk-replace help dev ui-compress \
|
sdk sdk-go sdk-ts sdk-ts-ui sdk-all help dev ui-compress print-version \
|
||||||
print-version
|
validate-spec check-tags doctor diff-swagger
|
||||||
|
|
||||||
|
# --- inputs/outputs for swagger (incremental) ---
|
||||||
|
DOCS_JSON := docs/swagger.json
|
||||||
|
DOCS_YAML := docs/swagger.yaml
|
||||||
|
# Prefer git for speed; fall back to find. Exclude UI dir.
|
||||||
|
GO_SRCS := $(shell (git ls-files '*.go' ':!$(UI_DIR)/**' 2>/dev/null || find . -name '*.go' -not -path './$(UI_DIR)/*' -type f))
|
||||||
|
|
||||||
|
# Rebuild swagger when Go sources change
|
||||||
|
$(DOCS_JSON) $(DOCS_YAML): $(GO_SRCS)
|
||||||
|
@echo ">> Generating Swagger docs..."
|
||||||
|
@if ! command -v swag >/dev/null 2>&1; then \
|
||||||
|
echo "Installing swag..."; \
|
||||||
|
$(GOINSTALL) github.com/swaggo/swag/cmd/swag@latest; \
|
||||||
|
fi
|
||||||
|
@rm -rf docs/swagger.* docs/docs.go
|
||||||
|
@swag init -g $(MAIN) -o docs
|
||||||
|
|
||||||
|
# --- spec validation + tag guard ---
|
||||||
|
validate-spec: $(DOCS_JSON) ## Validate docs/swagger.json and pin the core OpenAPI Generator version
|
||||||
|
@$(OGC_BIN) version-manager set "$(OPENAPI_GENERATOR_VERSION)"
|
||||||
|
@$(OGC_BIN) version
|
||||||
|
@$(OGC_BIN) validate -i $(DOCS_JSON)
|
||||||
|
@echo ">> Spec valid."
|
||||||
|
|
||||||
|
check-tags: $(DOCS_JSON) ## Check that Swagger tags contain no spaces/slashes (jq optional)
|
||||||
|
@echo ">> Checking tags for invalid characters (spaces or slashes)"
|
||||||
|
@if command -v jq >/dev/null 2>&1; then \
|
||||||
|
! jq -r '..|.tags? // empty | .[]' $(DOCS_JSON) | grep -Eq '[ /]'; \
|
||||||
|
else \
|
||||||
|
echo "jq not found; skipping tag check (install jq to enable)"; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optional: quick diff between JSON & YAML swagger (nice for drift)
|
||||||
|
diff-swagger: $(DOCS_JSON) $(DOCS_YAML) ## Show diff between swagger.json and swagger.yaml (requires yq)
|
||||||
|
@command -v yq >/dev/null 2>&1 || { echo "yq not found; brew install yq"; exit 1; }
|
||||||
|
@diff -u <(jq -S . $(DOCS_JSON)) <(yq -o=json -S '.' $(DOCS_YAML)) || true
|
||||||
|
|
||||||
# --- meta targets ---
|
# --- meta targets ---
|
||||||
all: build
|
all: build ## Default meta-target: build everything
|
||||||
prepare: fmt vet tidy upgrade
|
prepare: fmt vet tidy upgrade ## go fmt, vet, tidy, and upgrade module dependencies
|
||||||
|
|
||||||
# --- go hygiene ---
|
# --- go hygiene ---
|
||||||
fmt:
|
fmt: ## go fmt ./...
|
||||||
@$(GOCMD) fmt ./...
|
@$(GOCMD) fmt ./...
|
||||||
|
|
||||||
vet:
|
vet: ## go vet ./...
|
||||||
@$(GOCMD) vet ./...
|
@$(GOCMD) vet ./...
|
||||||
|
|
||||||
tidy:
|
tidy: ## go mod tidy
|
||||||
@$(GOCMD) mod tidy
|
@$(GOCMD) mod tidy
|
||||||
|
|
||||||
upgrade:
|
upgrade: ## Upgrade module requirements with go-mod-upgrade (best-effort)
|
||||||
@echo ">> Checking go-mod-upgrade..."
|
@echo ">> Checking go-mod-upgrade..."
|
||||||
@if [ -z "$(GMU)" ]; then \
|
@if [ -z "$(GMU)" ]; then \
|
||||||
echo "Installing go-mod-upgrade..."; \
|
echo "Installing go-mod-upgrade..."; \
|
||||||
@@ -82,7 +156,7 @@ upgrade:
|
|||||||
@go-mod-upgrade -f || true
|
@go-mod-upgrade -f || true
|
||||||
|
|
||||||
# --- ui ---
|
# --- ui ---
|
||||||
ui-install:
|
ui-install: ## Install frontend dependencies (yarn or npm)
|
||||||
@echo ">> Installing UI deps in $(UI_DIR)..."
|
@echo ">> Installing UI deps in $(UI_DIR)..."
|
||||||
@if [ -n "$(YARN)" ]; then \
|
@if [ -n "$(YARN)" ]; then \
|
||||||
cd $(UI_DIR) && yarn install --frozen-lockfile; \
|
cd $(UI_DIR) && yarn install --frozen-lockfile; \
|
||||||
@@ -92,7 +166,7 @@ ui-install:
|
|||||||
echo "Error: neither yarn nor npm is installed." >&2; exit 1; \
|
echo "Error: neither yarn nor npm is installed." >&2; exit 1; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ui-build: ui-install
|
ui-build: ui-install ## Build frontend (Vite)
|
||||||
@echo ">> Building UI in $(UI_DIR)..."
|
@echo ">> Building UI in $(UI_DIR)..."
|
||||||
@rm -rf $(UI_DEST_DIR)/dist
|
@rm -rf $(UI_DEST_DIR)/dist
|
||||||
@if [ -n "$(YARN)" ]; then \
|
@if [ -n "$(YARN)" ]; then \
|
||||||
@@ -101,7 +175,7 @@ ui-build: ui-install
|
|||||||
cd $(UI_DIR) && npm run build; \
|
cd $(UI_DIR) && npm run build; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ui-compress: ui-build
|
ui-compress: ui-build ## Precompress UI assets with brotli/gzip if available
|
||||||
@echo ">> Precompressing assets (brotli + gzip) in $(UI_DEST_DIR)/dist"
|
@echo ">> Precompressing assets (brotli + gzip) in $(UI_DEST_DIR)/dist"
|
||||||
@if [ -n "$(BROTLI)" ]; then \
|
@if [ -n "$(BROTLI)" ]; then \
|
||||||
find "$(UI_DEST_DIR)/dist" -type f \( -name '*.js' -o -name '*.css' -o -name '*.html' \) -print0 | \
|
find "$(UI_DEST_DIR)/dist" -type f \( -name '*.js' -o -name '*.css' -o -name '*.html' \) -print0 | \
|
||||||
@@ -112,25 +186,20 @@ ui-compress: ui-build
|
|||||||
xargs -0 -I{} gzip -kf {}; \
|
xargs -0 -I{} gzip -kf {}; \
|
||||||
else echo "gzip not found; skipping .gz"; fi
|
else echo "gzip not found; skipping .gz"; fi
|
||||||
|
|
||||||
ui: ui-compress
|
ui: ui-compress ## Build and precompress UI
|
||||||
|
|
||||||
# --- swagger ---
|
# --- swagger convenience phony (kept for UX) ---
|
||||||
swagger:
|
.PHONY: swagger
|
||||||
@echo ">> Generating Swagger docs..."
|
swagger: $(DOCS_JSON) ## Generate Swagger docs if stale
|
||||||
@if [ -z "$(SWAG)" ]; then \
|
@true
|
||||||
echo "Installing swag..."; \
|
|
||||||
$(GOINSTALL) github.com/swaggo/swag/cmd/swag@latest; \
|
|
||||||
fi
|
|
||||||
@rm -rf docs/swagger.* docs/docs.go
|
|
||||||
@swag init -g $(MAIN) -o docs
|
|
||||||
|
|
||||||
# --- build ---
|
# --- build ---
|
||||||
build: prepare ui swagger sdk-all
|
build: prepare ui swagger sdk-all ## Build everything: Go hygiene, UI, Swagger, SDKs, then Go binary
|
||||||
@echo ">> Building Go binary: $(BIN)"
|
@echo ">> Building Go binary: $(BIN)"
|
||||||
@$(GOCMD) build -trimpath -ldflags "$(LDFLAGS)" -o $(BIN) $(MAIN)
|
@$(GOCMD) build -trimpath -ldflags "$(LDFLAGS)" -o $(BIN) $(MAIN)
|
||||||
|
|
||||||
# Handy: print resolved version metadata
|
# Handy: print resolved version metadata
|
||||||
print-version:
|
print-version: ## Print ldflags/version metadata
|
||||||
@echo "VERSION = $(VERSION)"
|
@echo "VERSION = $(VERSION)"
|
||||||
@echo "COMMIT = $(COMMIT)"
|
@echo "COMMIT = $(COMMIT)"
|
||||||
@echo "DATE = $(DATE)"
|
@echo "DATE = $(DATE)"
|
||||||
@@ -138,7 +207,7 @@ print-version:
|
|||||||
@echo "LDFLAGS = $(LDFLAGS)"
|
@echo "LDFLAGS = $(LDFLAGS)"
|
||||||
|
|
||||||
# --- development ---
|
# --- development ---
|
||||||
dev: ui-install swagger
|
dev: ui-install swagger ## Run Vite dev server and Go API (serve)
|
||||||
@echo ">> Starting Vite (frontend) and Go API (backend) with dev env..."
|
@echo ">> Starting Vite (frontend) and Go API (backend) with dev env..."
|
||||||
@cd $(UI_DIR) && \
|
@cd $(UI_DIR) && \
|
||||||
( \
|
( \
|
||||||
@@ -154,124 +223,92 @@ dev: ui-install swagger
|
|||||||
wait \
|
wait \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# --- shared generator flags ---
|
||||||
|
GEN_COMMON := --enable-post-process-file $(ALIAS_FLAG) -i $(DOCS_JSON)
|
||||||
|
|
||||||
|
# --- DRY macro for openapi-generator generate ---
|
||||||
|
# Usage: $(call OGC_GENERATE,<generator>,<outdir>,<extra flags>)
|
||||||
|
define OGC_GENERATE
|
||||||
|
$(OGC_BIN) generate \
|
||||||
|
$(GEN_COMMON) \
|
||||||
|
-g $(1) \
|
||||||
|
-o $(2) \
|
||||||
|
$(3)
|
||||||
|
endef
|
||||||
|
|
||||||
|
# Convenience bundles
|
||||||
|
OAG_GIT_PROPS := --git-host "$(GIT_HOST_CLEAN)" --git-user-id "$(GIT_USER_CLEAN)" --git-repo-id "$(SDK_REPO_CLEAN)"
|
||||||
|
TS_PROPS := -p npmName=$(SDK_TS_NPM_NAME) -p npmVersion=$(SDK_TS_NPM_VER) $(SDK_TS_PROPS_FLAGS)
|
||||||
|
|
||||||
# --- sdk generation (Go) ---
|
# --- sdk generation (Go) ---
|
||||||
sdk-go: swagger
|
sdk-go: $(DOCS_JSON) validate-spec check-tags ## Generate Go SDK + tidy module
|
||||||
@echo ">> Generating Go SDK (module $(GIT_HOST)/$(GIT_USER)/$(SDK_REPO), Go $(GO_VERSION))..."
|
@echo ">> Generating Go SDK (module $(GIT_HOST_CLEAN)/$(GIT_USER_CLEAN)/$(SDK_REPO_CLEAN), Go $(GO_VERSION))..."
|
||||||
@set -e; \
|
@rm -rf "$(SDK_OUTDIR_CLEAN)"; mkdir -p "$(SDK_OUTDIR_CLEAN)"
|
||||||
export GO_POST_PROCESS_FILE="gofmt -w"; \
|
@$(call OGC_GENERATE,go,$(SDK_OUTDIR_CLEAN),--additional-properties=packageName=$(SDK_PKG_CLEAN) $(OAG_GIT_PROPS))
|
||||||
if [ -z "$(OGC)" ]; then \
|
@cd "$(SDK_OUTDIR_CLEAN)"; \
|
||||||
if [ -z "$(NPM)" ]; then \
|
|
||||||
echo "Error: npm is required to install openapi-generator-cli." >&2; exit 1; \
|
|
||||||
fi; \
|
|
||||||
echo "Installing openapi-generator-cli..."; \
|
|
||||||
$(NPM) i -g @openapitools/openapi-generator-cli; \
|
|
||||||
OGC_BIN=openapi-generator-cli; \
|
|
||||||
else \
|
|
||||||
OGC_BIN="$(OGC)"; \
|
|
||||||
fi; \
|
|
||||||
rm -rf "$(SDK_OUTDIR)"; \
|
|
||||||
mkdir -p "$(SDK_OUTDIR)"; \
|
|
||||||
"$$OGC_BIN" generate \
|
|
||||||
--enable-post-process-file \
|
|
||||||
--generate-alias-as-model \
|
|
||||||
-i docs/swagger.json \
|
|
||||||
-g go \
|
|
||||||
-o "$(SDK_OUTDIR)" \
|
|
||||||
--additional-properties=packageName=$(SDK_PKG) \
|
|
||||||
--git-host "$(GIT_HOST)" \
|
|
||||||
--git-user-id "$(GIT_USER)" \
|
|
||||||
--git-repo-id "$(SDK_REPO)"; \
|
|
||||||
cd "$(SDK_OUTDIR)"; \
|
|
||||||
$(GOCMD) mod edit -go=$(GO_VERSION); \
|
$(GOCMD) mod edit -go=$(GO_VERSION); \
|
||||||
$(GOCMD) mod tidy
|
$(GOCMD) mod tidy
|
||||||
|
|
||||||
# --- sdk generation (TypeScript) ---
|
# --- sdk generation (TypeScript) ---
|
||||||
sdk-ts: swagger
|
sdk-ts: $(DOCS_JSON) validate-spec check-tags ## Generate TypeScript SDK, format, and build
|
||||||
@set -e; \
|
@echo ">> Generating TypeScript SDK in $(SDK_TS_DIR_CLEAN)"
|
||||||
if [ -z "$(OGC)" ]; then \
|
@rm -rf "$(SDK_TS_DIR_CLEAN)"; mkdir -p "$(SDK_TS_DIR_CLEAN)"
|
||||||
if [ -z "$(NPM)" ]; then echo "Error: npm is required to install openapi-generator-cli." >&2; exit 1; fi; \
|
@$(call OGC_GENERATE,$(SDK_TS_GEN),$(SDK_TS_DIR_CLEAN),$(TS_PROPS))
|
||||||
echo "Installing openapi-generator-cli..."; \
|
@if command -v npx >/dev/null 2>&1; then \
|
||||||
$(NPM) i -g @openapitools/openapi-generator-cli; \
|
|
||||||
OGC_BIN=openapi-generator-cli; \
|
|
||||||
else \
|
|
||||||
OGC_BIN="$(OGC)"; \
|
|
||||||
fi; \
|
|
||||||
rm -rf "$(SDK_TS_DIR)"; \
|
|
||||||
mkdir -p "$(SDK_TS_DIR)"; \
|
|
||||||
"$$OGC_BIN" generate \
|
|
||||||
-i docs/swagger.json \
|
|
||||||
-g "$(SDK_TS_GEN)" \
|
|
||||||
-o "$(SDK_TS_DIR)" \
|
|
||||||
-p npmName=$(SDK_TS_NPM_NAME) \
|
|
||||||
-p npmVersion=$(SDK_TS_NPM_VER) \
|
|
||||||
$(SDK_TS_PROPS_FLAGS); \
|
|
||||||
if [ ! -d "$(SDK_TS_DIR)" ]; then \
|
|
||||||
echo "Generation failed: $(SDK_TS_DIR) not found." >&2; exit 1; \
|
|
||||||
fi; \
|
|
||||||
if command -v npx >/dev/null 2>&1; then \
|
|
||||||
echo ">> Prettier: formatting generated TS SDK"; \
|
echo ">> Prettier: formatting generated TS SDK"; \
|
||||||
cd "$(SDK_TS_DIR)" && npx --yes prettier -w . || true; \
|
cd "$(SDK_TS_DIR_CLEAN)" && npx --yes prettier -w . || true; \
|
||||||
fi; \
|
fi
|
||||||
echo ">> Installing & building TS SDK in $(SDK_TS_DIR)"; \
|
@echo ">> Installing & building TS SDK in $(SDK_TS_DIR_CLEAN)"
|
||||||
if command -v yarn >/dev/null 2>&1; then \
|
@if command -v yarn >/dev/null 2>&1; then \
|
||||||
cd "$(SDK_TS_DIR)" && yarn install --frozen-lockfile || true; \
|
cd "$(SDK_TS_DIR_CLEAN)" && yarn install --frozen-lockfile || true; \
|
||||||
cd "$(SDK_TS_DIR)" && yarn build || true; \
|
cd "$(SDK_TS_DIR_CLEAN)" && yarn build || true; \
|
||||||
elif command -v npm >/dev/null 2>&1; then \
|
elif command -v npm >/dev/null 2>&1; then \
|
||||||
cd "$(SDK_TS_DIR)" && npm ci || npm install || true; \
|
cd "$(SDK_TS_DIR_CLEAN)" && npm ci || npm install || true; \
|
||||||
cd "$(SDK_TS_DIR)" && npm run build || true; \
|
cd "$(SDK_TS_DIR_CLEAN)" && npm run build || true; \
|
||||||
else \
|
else \
|
||||||
echo "Warning: neither yarn nor npm is installed; skipping install/build for TS SDK."; \
|
echo "Warning: neither yarn nor npm is installed; skipping install/build for TS SDK."; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- sdk generation (TypeScript into UI/src) ---
|
# --- sdk generation (TypeScript into UI/src) ---
|
||||||
sdk-ts-ui: swagger
|
sdk-ts-ui: $(DOCS_JSON) validate-spec check-tags ## Generate TS SDK directly into UI src (no package files)
|
||||||
@echo ">> Generating TypeScript SDK directly into UI source: $(SDK_TS_UI_DIR)"
|
@echo ">> Generating TypeScript SDK directly into UI source: $(SDK_TS_UI_DIR_CLEAN)"
|
||||||
@set -e; \
|
@rm -rf "$(SDK_TS_UI_DIR_CLEAN)"; mkdir -p "$(SDK_TS_UI_DIR_CLEAN)"
|
||||||
if [ -z "$(OGC)" ]; then \
|
@$(call OGC_GENERATE,typescript-fetch,$(SDK_TS_UI_DIR_CLEAN),$(TS_PROPS))
|
||||||
if [ -z "$(NPM)" ]; then \
|
@if [ -d "$(SDK_TS_UI_DIR_CLEAN)/src" ]; then \
|
||||||
echo "Error: npm is required to install openapi-generator-cli." >&2; exit 1; \
|
mv "$(SDK_TS_UI_DIR_CLEAN)/src/"* "$(SDK_TS_UI_DIR_CLEAN)/"; \
|
||||||
fi; \
|
rm -rf "$(SDK_TS_UI_DIR_CLEAN)/src"; \
|
||||||
echo "Installing openapi-generator-cli..."; \
|
fi
|
||||||
$(NPM) i -g @openapitools/openapi-generator-cli; \
|
@rm -f "$(SDK_TS_UI_DIR_CLEAN)/package.json" "$(SDK_TS_UI_DIR_CLEAN)/tsconfig.json" "$(SDK_TS_UI_DIR_CLEAN)/README.md"
|
||||||
OGC_BIN=openapi-generator-cli; \
|
|
||||||
else \
|
|
||||||
OGC_BIN="$(OGC)"; \
|
|
||||||
fi; \
|
|
||||||
rm -rf "$(SDK_TS_UI_DIR)"; \
|
|
||||||
mkdir -p "$(SDK_TS_UI_DIR)"; \
|
|
||||||
"$$OGC_BIN" generate \
|
|
||||||
-i docs/swagger.json \
|
|
||||||
-g typescript-fetch \
|
|
||||||
-o "$(SDK_TS_UI_DIR)" \
|
|
||||||
-p npmName=$(SDK_TS_NPM_NAME) \
|
|
||||||
-p npmVersion=$(SDK_TS_NPM_VER) \
|
|
||||||
$(SDK_TS_PROPS_FLAGS); \
|
|
||||||
# --- move src/* up one level ---
|
|
||||||
@if [ -d "$(SDK_TS_UI_DIR)/src" ]; then \
|
|
||||||
mv "$(SDK_TS_UI_DIR)/src/"* "$(SDK_TS_UI_DIR)/"; \
|
|
||||||
rm -rf "$(SDK_TS_UI_DIR)/src"; \
|
|
||||||
fi; \
|
|
||||||
rm -f "$(SDK_TS_UI_DIR)/package.json" "$(SDK_TS_UI_DIR)/tsconfig.json" "$(SDK_TS_UI_DIR)/README.md"
|
|
||||||
|
|
||||||
# convenience
|
# --- convenience ---
|
||||||
sdk-all: sdk-go sdk-ts sdk-ts-ui
|
sdk-all: sdk-go sdk-ts sdk-ts-ui ## Generate Go + TS SDKs (tip: run with "make -j sdk-all" for parallel)
|
||||||
sdk: sdk-go
|
sdk: sdk-go ## Alias for sdk-go
|
||||||
|
|
||||||
# --- clean/help ---
|
# --- clean/help ---
|
||||||
clean:
|
clean: ## Clean build artifacts, Swagger outputs, UI dist, and SDKs
|
||||||
@echo ">> Cleaning artifacts..."
|
@echo ">> Cleaning artifacts..."
|
||||||
@rm -rf "$(BIN)" docs/swagger.* docs/docs.go $(UI_DEST_DIR)/dist $(UI_DIR)/dist $(UI_DIR)/node_modules "$(SDK_OUTDIR)" "$(SDK_TS_OUTDIR)"
|
@rm -rf "$(BIN)" docs/swagger.* docs/docs.go \
|
||||||
|
"$(UI_DEST_DIR)/dist" "$(UI_DIR)/dist" "$(UI_DIR)/node_modules" \
|
||||||
|
"$(SDK_OUTDIR_CLEAN)" "$(SDK_TS_DIR_CLEAN)" "$(SDK_TS_UI_DIR_CLEAN)"
|
||||||
|
|
||||||
help:
|
doctor: ## Print environment diagnostics (shell, versions, generator availability)
|
||||||
@echo "Targets:"
|
@echo ">> Make is using shell: $(SHELL)"
|
||||||
@echo " build - fmt, vet, tidy, upgrade, build UI, generate Swagger, build Go binary (with ldflags)"
|
@{ \
|
||||||
@echo " ui - build the Vite UI and copy to $(UI_DEST_DIR)/dist (with compression)"
|
echo ">> Detected runtime shell process: $$0"; \
|
||||||
@echo " swagger - (re)generate Swagger docs using swag"
|
command -v bash >/dev/null 2>&1 || { echo "bash not found. On macOS: brew install bash"; exit 1; }; \
|
||||||
@echo " sdk-go (sdk) - generate Go SDK with correct module path and Go version"
|
echo ">> Versions:"; \
|
||||||
@echo " sdk-ts - generate TypeScript SDK (typescript-fetch) with package.json"
|
bash --version | head -1 || true; \
|
||||||
@echo " sdk-ts-ui - generate TypeScript SDK directly into ui/src for inline consumption"
|
go version || true; \
|
||||||
@echo " sdk-all - generate both Go and TypeScript SDKs"
|
node -v || true; \
|
||||||
@echo " dev - run Vite UI dev server + Go API"
|
npm -v || true; \
|
||||||
@echo " clean - remove binary, Swagger outputs, UI dist, and SDKs"
|
npx -v || true; \
|
||||||
@echo " prepare - fmt, vet, tidy, upgrade deps"
|
jq --version || true; \
|
||||||
@echo " print-version - show computed ldflags values"
|
echo ">> OpenAPI Generator (wrapper) available via npx:"; \
|
||||||
|
$(OGC_BIN) version || true; \
|
||||||
|
}
|
||||||
|
|
||||||
|
help: ## Show this help
|
||||||
|
@grep -hE '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \
|
||||||
|
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||||
|
|
||||||
|
# ========= end Makefile =========
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -882,7 +882,7 @@ paths:
|
|||||||
- ApiKeyAuth: []
|
- ApiKeyAuth: []
|
||||||
summary: List my API keys
|
summary: List my API keys
|
||||||
tags:
|
tags:
|
||||||
- Me / API Keys
|
- MeAPIKeys
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
@@ -908,7 +908,7 @@ paths:
|
|||||||
- ApiKeyAuth: []
|
- ApiKeyAuth: []
|
||||||
summary: Create a new user API key
|
summary: Create a new user API key
|
||||||
tags:
|
tags:
|
||||||
- Me / API Keys
|
- MeAPIKeys
|
||||||
/me/api-keys/{id}:
|
/me/api-keys/{id}:
|
||||||
delete:
|
delete:
|
||||||
operationId: DeleteUserAPIKey
|
operationId: DeleteUserAPIKey
|
||||||
@@ -927,7 +927,7 @@ paths:
|
|||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: Delete a user API key
|
summary: Delete a user API key
|
||||||
tags:
|
tags:
|
||||||
- Me / API Keys
|
- MeAPIKeys
|
||||||
/orgs:
|
/orgs:
|
||||||
get:
|
get:
|
||||||
operationId: listMyOrgs
|
operationId: listMyOrgs
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ func NewRuntime() *Runtime {
|
|||||||
&models.Server{},
|
&models.Server{},
|
||||||
&models.Taint{},
|
&models.Taint{},
|
||||||
&models.Label{},
|
&models.Label{},
|
||||||
|
&models.Annotation{},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error initializing database: %v", err)
|
log.Fatalf("Error initializing database: %v", err)
|
||||||
|
|||||||
14
internal/common/audit.go
Normal file
14
internal/common/audit.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AuditFields struct {
|
||||||
|
ID uuid.UUID `json:"id" gorm:"type:uuid;default:gen_random_uuid()"`
|
||||||
|
OrganizationID uuid.UUID `json:"organization_id" gorm:"type:uuid;index"`
|
||||||
|
CreatedAt time.Time `json:"created_at,omitempty" gorm:"column:created_at;not null;default:now()"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at,omitempty" gorm:"autoUpdateTime;column:updated_at;not null;default:now()"`
|
||||||
|
}
|
||||||
21
internal/handlers/annotations.go
Normal file
21
internal/handlers/annotations.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
// ListAnnotations godoc
|
||||||
|
// @ID ListAnnotations
|
||||||
|
// @Summary List annotations (org scoped)
|
||||||
|
// @Description Returns annotations for the organization in X-Org-ID. Filters: `name`, `value`, and `q` (name contains). Add `include=node_pools` to include linked node pools.
|
||||||
|
// @Tags Annotations
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param X-Org-ID header string false "Organization UUID"
|
||||||
|
// @Param name query string false "Exact name"
|
||||||
|
// @Param value query string false "Exact value"
|
||||||
|
// @Param q query string false "name contains (case-insensitive)"
|
||||||
|
// @Success 200 {array} annotationResponse
|
||||||
|
// @Failure 401 {string} string "Unauthorized"
|
||||||
|
// @Failure 403 {string} string "organization required"
|
||||||
|
// @Failure 500 {string} string "failed to list annotations"
|
||||||
|
// @Router /api/v1/annotations [get]
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Security OrgKeyAuth
|
||||||
|
// @Security OrgSecretAuth
|
||||||
19
internal/handlers/dto/annotations.go
Normal file
19
internal/handlers/dto/annotations.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import "github.com/glueops/autoglue/internal/common"
|
||||||
|
|
||||||
|
type AnnotationResponse struct {
|
||||||
|
common.AuditFields
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateAnnotationRequest struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateAnnotationRequest struct {
|
||||||
|
Key *string `json:"key,omitempty"`
|
||||||
|
Value *string `json:"value,omitempty"`
|
||||||
|
}
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
import "github.com/google/uuid"
|
import (
|
||||||
|
"github.com/glueops/autoglue/internal/common"
|
||||||
|
)
|
||||||
|
|
||||||
type LabelResponse struct {
|
type LabelResponse struct {
|
||||||
ID uuid.UUID `json:"id"`
|
common.AuditFields
|
||||||
OrganizationID uuid.UUID `json:"organization_id"`
|
Key string `json:"key"`
|
||||||
Key string `json:"key"`
|
Value string `json:"value"`
|
||||||
Value string `json:"value"`
|
|
||||||
CreatedAt string `json:"created_at,omitempty"`
|
|
||||||
UpdatedAt string `json:"updated_at,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateLabelRequest struct {
|
type CreateLabelRequest struct {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/glueops/autoglue/internal/api/httpmiddleware"
|
"github.com/glueops/autoglue/internal/api/httpmiddleware"
|
||||||
|
"github.com/glueops/autoglue/internal/common"
|
||||||
"github.com/glueops/autoglue/internal/handlers/dto"
|
"github.com/glueops/autoglue/internal/handlers/dto"
|
||||||
"github.com/glueops/autoglue/internal/models"
|
"github.com/glueops/autoglue/internal/models"
|
||||||
"github.com/glueops/autoglue/internal/utils"
|
"github.com/glueops/autoglue/internal/utils"
|
||||||
@@ -53,20 +54,12 @@ func ListLabels(db *gorm.DB) http.HandlerFunc {
|
|||||||
if needle := strings.TrimSpace(r.URL.Query().Get("q")); needle != "" {
|
if needle := strings.TrimSpace(r.URL.Query().Get("q")); needle != "" {
|
||||||
q = q.Where(`key ILIKE ?`, "%"+needle+"%")
|
q = q.Where(`key ILIKE ?`, "%"+needle+"%")
|
||||||
}
|
}
|
||||||
var rows []models.Label
|
var out []dto.LabelResponse
|
||||||
if err := q.Order("created_at DESC").Find(&rows).Error; err != nil {
|
if err := q.Model(&models.Label{}).Order("created_at DESC").Scan(&out).Error; err != nil {
|
||||||
utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error")
|
utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
out := make([]dto.LabelResponse, 0, len(rows))
|
|
||||||
for _, row := range rows {
|
|
||||||
out = append(out, dto.LabelResponse{
|
|
||||||
Key: row.Key,
|
|
||||||
Value: row.Value,
|
|
||||||
ID: row.ID,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
utils.WriteJSON(w, http.StatusOK, out)
|
utils.WriteJSON(w, http.StatusOK, out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,17 +97,14 @@ func GetLabel(db *gorm.DB) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var row models.Label
|
var out dto.LabelResponse
|
||||||
if err := db.Where("id = ? AND organization_id = ?", id, orgID).First(&row).Error; err != nil {
|
if err := db.Model(&models.Label{}).Where("id = ? AND organization_id = ?", id, orgID).Limit(1).Scan(&out).Error; err != nil {
|
||||||
utils.WriteError(w, http.StatusNotFound, "label_not_found", "label not found")
|
if out.ID == uuid.Nil {
|
||||||
return
|
utils.WriteError(w, http.StatusNotFound, "label_not_found", "label not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out := dto.LabelResponse{
|
|
||||||
Key: row.Key,
|
|
||||||
Value: row.Value,
|
|
||||||
ID: row.ID,
|
|
||||||
}
|
|
||||||
utils.WriteJSON(w, http.StatusOK, out)
|
utils.WriteJSON(w, http.StatusOK, out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,9 +150,9 @@ func CreateLabel(db *gorm.DB) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
l := models.Label{
|
l := models.Label{
|
||||||
OrganizationID: orgID,
|
AuditFields: common.AuditFields{OrganizationID: orgID},
|
||||||
Key: req.Key,
|
Key: req.Key,
|
||||||
Value: req.Value,
|
Value: req.Value,
|
||||||
}
|
}
|
||||||
if err := db.Create(&l).Error; err != nil {
|
if err := db.Create(&l).Error; err != nil {
|
||||||
utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error")
|
utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error")
|
||||||
@@ -170,14 +160,15 @@ func CreateLabel(db *gorm.DB) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
out := dto.LabelResponse{
|
out := dto.LabelResponse{
|
||||||
ID: l.ID,
|
AuditFields: l.AuditFields,
|
||||||
Key: l.Key,
|
Key: l.Key,
|
||||||
Value: l.Value,
|
Value: l.Value,
|
||||||
}
|
}
|
||||||
utils.WriteJSON(w, http.StatusCreated, out)
|
utils.WriteJSON(w, http.StatusCreated, out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateLabel godoc
|
||||||
// UpdateLabel godoc
|
// UpdateLabel godoc
|
||||||
// @ID UpdateLabel
|
// @ID UpdateLabel
|
||||||
// @Summary Update label (org scoped)
|
// @Summary Update label (org scoped)
|
||||||
@@ -228,22 +219,22 @@ func UpdateLabel(db *gorm.DB) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
next := l
|
|
||||||
if req.Key != nil {
|
if req.Key != nil {
|
||||||
next.Key = strings.TrimSpace(*req.Key)
|
l.Key = strings.TrimSpace(*req.Key)
|
||||||
}
|
}
|
||||||
if req.Value != nil {
|
if req.Value != nil {
|
||||||
next.Value = strings.TrimSpace(*req.Value)
|
l.Value = strings.TrimSpace(*req.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := db.Save(&next).Error; err != nil {
|
if err := db.Save(&l).Error; err != nil {
|
||||||
utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error")
|
utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
out := dto.LabelResponse{
|
out := dto.LabelResponse{
|
||||||
ID: next.ID,
|
AuditFields: l.AuditFields,
|
||||||
Key: next.Key,
|
Key: l.Key,
|
||||||
Value: next.Value,
|
Value: l.Value,
|
||||||
}
|
}
|
||||||
utils.WriteJSON(w, http.StatusOK, out)
|
utils.WriteJSON(w, http.StatusOK, out)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ type userAPIKeyOut struct {
|
|||||||
// ListUserAPIKeys godoc
|
// ListUserAPIKeys godoc
|
||||||
// @ID ListUserAPIKeys
|
// @ID ListUserAPIKeys
|
||||||
// @Summary List my API keys
|
// @Summary List my API keys
|
||||||
// @Tags Me / API Keys
|
// @Tags MeAPIKeys
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {array} userAPIKeyOut
|
// @Success 200 {array} userAPIKeyOut
|
||||||
// @Router /me/api-keys [get]
|
// @Router /me/api-keys [get]
|
||||||
@@ -67,7 +67,7 @@ type createUserKeyRequest struct {
|
|||||||
// @ID CreateUserAPIKey
|
// @ID CreateUserAPIKey
|
||||||
// @Summary Create a new user API key
|
// @Summary Create a new user API key
|
||||||
// @Description Returns the plaintext key once. Store it securely on the client side.
|
// @Description Returns the plaintext key once. Store it securely on the client side.
|
||||||
// @Tags Me / API Keys
|
// @Tags MeAPIKeys
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body createUserKeyRequest true "Key options"
|
// @Param body body createUserKeyRequest true "Key options"
|
||||||
@@ -120,7 +120,7 @@ func CreateUserAPIKey(db *gorm.DB) http.HandlerFunc {
|
|||||||
// DeleteUserAPIKey godoc
|
// DeleteUserAPIKey godoc
|
||||||
// @ID DeleteUserAPIKey
|
// @ID DeleteUserAPIKey
|
||||||
// @Summary Delete a user API key
|
// @Summary Delete a user API key
|
||||||
// @Tags Me / API Keys
|
// @Tags MeAPIKeys
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path string true "Key ID (UUID)"
|
// @Param id path string true "Key ID (UUID)"
|
||||||
// @Success 204 "No Content"
|
// @Success 204 "No Content"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/glueops/autoglue/internal/api/httpmiddleware"
|
"github.com/glueops/autoglue/internal/api/httpmiddleware"
|
||||||
"github.com/glueops/autoglue/internal/handlers/dto"
|
"github.com/glueops/autoglue/internal/handlers/dto"
|
||||||
@@ -63,10 +64,13 @@ func ListTaints(db *gorm.DB) http.HandlerFunc {
|
|||||||
out := make([]dto.TaintResponse, 0, len(rows))
|
out := make([]dto.TaintResponse, 0, len(rows))
|
||||||
for _, row := range rows {
|
for _, row := range rows {
|
||||||
out = append(out, dto.TaintResponse{
|
out = append(out, dto.TaintResponse{
|
||||||
ID: row.ID,
|
ID: row.ID,
|
||||||
Key: row.Key,
|
Key: row.Key,
|
||||||
Value: row.Value,
|
Value: row.Value,
|
||||||
Effect: row.Effect,
|
Effect: row.Effect,
|
||||||
|
OrganizationID: row.OrganizationID,
|
||||||
|
CreatedAt: row.CreatedAt.UTC().Format(time.RFC3339),
|
||||||
|
UpdatedAt: row.UpdatedAt.UTC().Format(time.RFC3339),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
utils.WriteJSON(w, http.StatusOK, out)
|
utils.WriteJSON(w, http.StatusOK, out)
|
||||||
@@ -115,10 +119,13 @@ func GetTaint(db *gorm.DB) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
out := dto.TaintResponse{
|
out := dto.TaintResponse{
|
||||||
ID: row.ID,
|
ID: row.ID,
|
||||||
Key: row.Key,
|
Key: row.Key,
|
||||||
Value: row.Value,
|
Value: row.Value,
|
||||||
Effect: row.Effect,
|
Effect: row.Effect,
|
||||||
|
OrganizationID: row.OrganizationID,
|
||||||
|
CreatedAt: row.CreatedAt.UTC().Format(time.RFC3339),
|
||||||
|
UpdatedAt: row.UpdatedAt.UTC().Format(time.RFC3339),
|
||||||
}
|
}
|
||||||
utils.WriteJSON(w, http.StatusOK, out)
|
utils.WriteJSON(w, http.StatusOK, out)
|
||||||
}
|
}
|
||||||
@@ -182,10 +189,13 @@ func CreateTaint(db *gorm.DB) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
out := dto.TaintResponse{
|
out := dto.TaintResponse{
|
||||||
ID: t.ID,
|
ID: t.ID,
|
||||||
Key: t.Key,
|
Key: t.Key,
|
||||||
Value: t.Value,
|
Value: t.Value,
|
||||||
Effect: t.Effect,
|
Effect: t.Effect,
|
||||||
|
OrganizationID: t.OrganizationID,
|
||||||
|
CreatedAt: t.CreatedAt.UTC().Format(time.RFC3339),
|
||||||
|
UpdatedAt: t.UpdatedAt.UTC().Format(time.RFC3339),
|
||||||
}
|
}
|
||||||
utils.WriteJSON(w, http.StatusCreated, out)
|
utils.WriteJSON(w, http.StatusCreated, out)
|
||||||
}
|
}
|
||||||
@@ -268,10 +278,13 @@ func UpdateTaint(db *gorm.DB) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
out := dto.TaintResponse{
|
out := dto.TaintResponse{
|
||||||
ID: next.ID,
|
ID: next.ID,
|
||||||
Key: next.Key,
|
Key: next.Key,
|
||||||
Value: next.Value,
|
Value: next.Value,
|
||||||
Effect: next.Effect,
|
Effect: next.Effect,
|
||||||
|
OrganizationID: next.OrganizationID,
|
||||||
|
CreatedAt: next.CreatedAt.UTC().Format(time.RFC3339),
|
||||||
|
UpdatedAt: next.UpdatedAt.UTC().Format(time.RFC3339),
|
||||||
}
|
}
|
||||||
utils.WriteJSON(w, http.StatusOK, out)
|
utils.WriteJSON(w, http.StatusOK, out)
|
||||||
}
|
}
|
||||||
|
|||||||
12
internal/models/annotation.go
Normal file
12
internal/models/annotation.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/glueops/autoglue/internal/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Annotation struct {
|
||||||
|
common.AuditFields `gorm:"embedded"`
|
||||||
|
Organization Organization `gorm:"foreignKey:OrganizationID;constraint:OnDelete:CASCADE" json:"organization"`
|
||||||
|
Key string `gorm:"not null" json:"key"`
|
||||||
|
Value string `gorm:"not null" json:"value"`
|
||||||
|
}
|
||||||
@@ -1,18 +1,13 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"github.com/glueops/autoglue/internal/common"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Label struct {
|
type Label struct {
|
||||||
ID uuid.UUID `gorm:"type:uuid;default:gen_random_uuid();primaryKey" json:"id"`
|
common.AuditFields
|
||||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null" json:"organization_id"`
|
Organization Organization `gorm:"foreignKey:OrganizationID;constraint:OnDelete:CASCADE" json:"organization"`
|
||||||
Organization Organization `gorm:"foreignKey:OrganizationID;constraint:OnDelete:CASCADE" json:"organization"`
|
Key string `gorm:"not null" json:"key"`
|
||||||
Key string `gorm:"not null" json:"key"`
|
Value string `gorm:"not null" json:"value"`
|
||||||
Value string `gorm:"not null" json:"value"`
|
NodePools []NodePool `gorm:"many2many:node_labels;constraint:OnDelete:CASCADE" json:"servers,omitempty"`
|
||||||
NodePools []NodePool `gorm:"many2many:node_labels;constraint:OnDelete:CASCADE" json:"servers,omitempty"`
|
|
||||||
CreatedAt time.Time `gorm:"column:created_at;not null;default:now()" json:"created_at"`
|
|
||||||
UpdatedAt time.Time `gorm:"autoUpdateTime;column:updated_at;not null;default:now()" json:"updated_at"`
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ type NodePool struct {
|
|||||||
Organization Organization `gorm:"foreignKey:OrganizationID;constraint:OnDelete:CASCADE" json:"organization"`
|
Organization Organization `gorm:"foreignKey:OrganizationID;constraint:OnDelete:CASCADE" json:"organization"`
|
||||||
Name string `gorm:"not null" json:"name"`
|
Name string `gorm:"not null" json:"name"`
|
||||||
Servers []Server `gorm:"many2many:node_servers;constraint:OnDelete:CASCADE" json:"servers,omitempty"`
|
Servers []Server `gorm:"many2many:node_servers;constraint:OnDelete:CASCADE" json:"servers,omitempty"`
|
||||||
//Annotations []Annotation `gorm:"many2many:node_annotations;constraint:OnDelete:CASCADE" json:"annotations,omitempty"`
|
Annotations []Annotation `gorm:"many2many:node_annotations;constraint:OnDelete:CASCADE" json:"annotations,omitempty"`
|
||||||
Labels []Label `gorm:"many2many:node_labels;constraint:OnDelete:CASCADE" json:"labels,omitempty"`
|
Labels []Label `gorm:"many2many:node_labels;constraint:OnDelete:CASCADE" json:"labels,omitempty"`
|
||||||
Taints []Taint `gorm:"many2many:node_taints;constraint:OnDelete:CASCADE" json:"taints,omitempty"`
|
Taints []Taint `gorm:"many2many:node_taints;constraint:OnDelete:CASCADE" json:"taints,omitempty"`
|
||||||
//Clusters []Cluster `gorm:"many2many:cluster_node_pools;constraint:OnDelete:CASCADE" json:"clusters,omitempty"`
|
//Clusters []Cluster `gorm:"many2many:cluster_node_pools;constraint:OnDelete:CASCADE" json:"clusters,omitempty"`
|
||||||
Topology string `gorm:"not null" json:"topology,omitempty"` // stacked or external
|
Topology string `gorm:"not null" json:"topology,omitempty"` // stacked or external
|
||||||
Role string `gorm:"not null" json:"role,omitempty"` // master, worker, or etcd (etcd only if topology = external
|
Role string `gorm:"not null" json:"role,omitempty"` // master, worker, or etcd (etcd only if topology = external
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
.gitignore
|
.gitignore
|
||||||
|
.openapi-generator-ignore
|
||||||
.travis.yml
|
.travis.yml
|
||||||
README.md
|
README.md
|
||||||
api/openapi.yaml
|
api/openapi.yaml
|
||||||
@@ -90,4 +91,12 @@ model_models_user.go
|
|||||||
model_models_user_email.go
|
model_models_user_email.go
|
||||||
model_utils_error_response.go
|
model_utils_error_response.go
|
||||||
response.go
|
response.go
|
||||||
|
test/api_auth_test.go
|
||||||
|
test/api_labels_test.go
|
||||||
|
test/api_me_api_keys_test.go
|
||||||
|
test/api_me_test.go
|
||||||
|
test/api_orgs_test.go
|
||||||
|
test/api_servers_test.go
|
||||||
|
test/api_ssh_test.go
|
||||||
|
test/api_taints_test.go
|
||||||
utils.go
|
utils.go
|
||||||
|
|||||||
@@ -455,7 +455,7 @@ paths:
|
|||||||
- ApiKeyAuth: []
|
- ApiKeyAuth: []
|
||||||
summary: List my API keys
|
summary: List my API keys
|
||||||
tags:
|
tags:
|
||||||
- Me / API Keys
|
- MeAPIKeys
|
||||||
post:
|
post:
|
||||||
description: Returns the plaintext key once. Store it securely on the client
|
description: Returns the plaintext key once. Store it securely on the client
|
||||||
side.
|
side.
|
||||||
@@ -479,7 +479,7 @@ paths:
|
|||||||
- ApiKeyAuth: []
|
- ApiKeyAuth: []
|
||||||
summary: Create a new user API key
|
summary: Create a new user API key
|
||||||
tags:
|
tags:
|
||||||
- Me / API Keys
|
- MeAPIKeys
|
||||||
x-codegen-request-body-name: body
|
x-codegen-request-body-name: body
|
||||||
/me/api-keys/{id}:
|
/me/api-keys/{id}:
|
||||||
delete:
|
delete:
|
||||||
@@ -499,7 +499,7 @@ paths:
|
|||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: Delete a user API key
|
summary: Delete a user API key
|
||||||
tags:
|
tags:
|
||||||
- Me / API Keys
|
- MeAPIKeys
|
||||||
/orgs:
|
/orgs:
|
||||||
get:
|
get:
|
||||||
operationId: listMyOrgs
|
operationId: listMyOrgs
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
module github.com/glueops/autoglue-sdk-go
|
module github.com/glueops/autoglue-sdk-go
|
||||||
|
|
||||||
go 1.23
|
go 1.25.3
|
||||||
|
|
||||||
|
require github.com/stretchr/testify v1.11.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg=
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
|
|||||||
@@ -290,7 +290,62 @@ export const LabelsPage = () => {
|
|||||||
</Table>
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<pre>{JSON.stringify(labelsQ, null, 2)}</pre>
|
|
||||||
|
{/* Update dialog */}
|
||||||
|
<Dialog open={updateOpen} onOpenChange={setUpdateOpen}>
|
||||||
|
<DialogContent className="sm:max-w-lg">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Edit taint</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
<Form {...updateForm}>
|
||||||
|
<form
|
||||||
|
className="space-y-4"
|
||||||
|
onSubmit={updateForm.handleSubmit((values) => {
|
||||||
|
if (!editingId) return
|
||||||
|
updateMut.mutate({ id: editingId, values })
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<FormField
|
||||||
|
control={updateForm.control}
|
||||||
|
name="key"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Key</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input placeholder="dedicated" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
control={updateForm.control}
|
||||||
|
name="value"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Value (optional)</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input placeholder="gpu" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<DialogFooter className="gap-2">
|
||||||
|
<Button type="button" variant="outline" onClick={() => setUpdateOpen(false)}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button type="submit" disabled={updateMut.isPending}>
|
||||||
|
{updateMut.isPending ? "Saving…" : "Save changes"}
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
<pre>{JSON.stringify(labelsQ.data, null, 2)}</pre>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -816,6 +816,7 @@ export const ServerPage = () => {
|
|||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
<pre>{JSON.stringify(serverQ.data, null, 2)}</pre>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -470,6 +470,7 @@ export const SshPage = () => {
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
|
<pre>{JSON.stringify(sshQ.data, null, 2)}</pre>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -422,6 +422,7 @@ export const TaintsPage = () => {
|
|||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
<pre>{JSON.stringify(taintsQ.data, null, 2)}</pre>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user