Merge pull request #51300 from rafaelcamelo31/50486_api_move_scripts

api: move scripts to generate and validate swagger to api module
This commit is contained in:
Sebastiaan van Stijn
2025-12-11 21:35:38 +01:00
committed by GitHub
12 changed files with 193 additions and 86 deletions

25
api/Dockerfile Normal file
View File

@@ -0,0 +1,25 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.25.4
FROM golang:${GO_VERSION}-alpine AS base
RUN apk add --no-cache bash make yamllint
CMD ["/bin/bash"]
# go-swagger
FROM base AS swagger
WORKDIR /go/src/github.com/go-swagger/go-swagger
# GO_SWAGGER_VERSION specifies the version of the go-swagger binary to install.
# Go-swagger is used in CI for generating types from swagger.yaml in
# api/scripts/generate-swagger-api.sh
ARG GO_SWAGGER_VERSION=v0.33.1
ARG TARGETPLATFORM
RUN --mount=type=cache,target=/root/.cache/go-build,id=swagger-build-$TARGETPLATFORM \
--mount=type=cache,target=/go/pkg/mod \
CGO_ENABLED=0 go install "github.com/go-swagger/go-swagger/cmd/swagger@${GO_SWAGGER_VERSION}" && \
/go/bin/swagger version
# dev is a dev-environment to work with the api module.
FROM base AS dev
COPY --from=swagger /go/bin/swagger /usr/local/bin/swagger
WORKDIR /go/src/github.com/moby/moby/api

64
api/Makefile Normal file
View File

@@ -0,0 +1,64 @@
# API Module Makefile
# This Makefile provides targets for the swagger generation and validation
# which are specific to the API module.
DOCKER ?= docker
BUILDX ?= $(DOCKER) buildx
API_DIR := $(CURDIR)
PROJECT_PATH := /go/src/github.com/moby/moby
DOCKER_MOUNT := -v "$(API_DIR):$(PROJECT_PATH)/api"
DOCKER_IMAGE := docker-api-dev
DOCKER_WORKDIR := -w $(PROJECT_PATH)/api
DOCKER_FLAGS := $(DOCKER) run --rm $(DOCKER_MOUNT) $(DOCKER_WORKDIR)
DOCKER_RUN := $(DOCKER_FLAGS) "$(DOCKER_IMAGE)"
DOCKER_CONTAINER_NAME := $(if $(CONTAINER_NAME),--name $(CONTAINER_NAME),)
BUILD_CMD := $(BUILDX) build
GO_VERSION ?= 1.25.4
SWAGGER_VERSION ?= v0.33.1
SWAGGER_DOCS_PORT ?= 9000
.DEFAULT_GOAL := help
.PHONY: build
build:
$(BUILD_CMD) \
--build-arg GO_VERSION=$(GO_VERSION) \
--build-arg SWAGGER_VERSION=$(SWAGGER_VERSION) \
--target dev \
--load \
-t "$(DOCKER_IMAGE)" \
-f Dockerfile \
.
.PHONY: swagger-gen
swagger-gen: build ## generate swagger API types
$(DOCKER_RUN) ./scripts/generate-swagger-api.sh
.PHONY: swagger-docs
swagger-docs: ## preview the API documentation
@echo "API docs preview will be running at http://localhost:$(SWAGGER_DOCS_PORT)"
@docker run --rm \
-v $(PWD)/:/usr/share/nginx/html/swagger/ \
-e 'REDOC_OPTIONS=hide-hostname="true" lazy-rendering' \
-e SPEC_URL="swagger/swagger.yaml" \
-p $(SWAGGER_DOCS_PORT):80 \
redocly/redoc:v2.5.1
.PHONY: validate-swagger
validate-swagger: build ## validate the swagger.yaml file
$(DOCKER_RUN) ./scripts/validate-swagger.sh
.PHONY: validate-swagger-gen
validate-swagger-gen: build ## validate generated types are up-to-date
$(DOCKER_RUN) ./scripts/validate-swagger-gen.sh
.PHONY: help
help: ## display this help message
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z0-9_-]+:.*?## / {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)

View File

@@ -0,0 +1,127 @@
#!/bin/bash
# vim: set noexpandtab:
# -*- indent-tabs-mode: t -*-
set -eu
API_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
generate_model() {
local package="$1"
shift
mapfile
swagger generate model --spec="${API_DIR}/swagger.yaml" \
--target="${API_DIR}" --model-package="$package" \
--config-file="${API_DIR}/swagger-gen.yaml" \
--template-dir="${API_DIR}/templates" --allow-template-override \
"$@" \
$(printf -- '--name=%s ' "${MAPFILE[@]}")
}
generate_operation() {
mapfile
swagger generate operation --spec="${API_DIR}/swagger.yaml" \
--target="${API_DIR}" --api-package=types --model-package=types \
--config-file="${API_DIR}/swagger-gen.yaml" \
--template-dir="${API_DIR}/templates" --allow-template-override \
"$@" \
$(printf -- '--name=%s ' "${MAPFILE[@]}")
}
# /==================================================================\
# | |
# | ATTENTION: |
# | |
# | Sort model package stanzas and model/operation names |
# | *** ALPHABETICALLY *** |
# | to reduce the likelihood of merge conflicts. |
# | |
# \==================================================================/
#region -------- Models --------
generate_model types/build <<- 'EOT'
BuildCacheDiskUsage
EOT
generate_model types/common <<- 'EOT'
ErrorResponse
IDResponse
EOT
generate_model types/container <<- 'EOT'
ChangeType
ContainerCreateResponse
ContainerTopResponse
ContainerUpdateResponse
ContainerWaitExitError
ContainerWaitResponse
ContainersDiskUsage
FilesystemChange
PortSummary
EOT
generate_model types/image <<- 'EOT'
ImageDeleteResponseItem
ImagesDiskUsage
EOT
# ImageSummary
# TODO: Restore when go-swagger is updated
# See https://github.com/moby/moby/pull/47526#discussion_r1551800022
generate_model types/network --keep-spec-order --additional-initialism=IPAM <<- 'EOT'
ConfigReference
EndpointResource
IPAMStatus
Network
NetworkConnectRequest
NetworkCreateResponse
NetworkDisconnectRequest
NetworkInspect
NetworkStatus
NetworkSummary
NetworkTaskInfo
PeerInfo
ServiceInfo
SubnetStatus
EOT
generate_model types/plugin <<- 'EOT'
Plugin
PluginDevice
PluginEnv
PluginMount
EOT
generate_model types/registry <<- 'EOT'
AuthResponse
EOT
generate_model types/storage <<- 'EOT'
DriverData
RootFSStorage
RootFSStorageSnapshot
Storage
EOT
generate_model types/swarm <<- 'EOT'
ServiceCreateResponse
ServiceUpdateResponse
EOT
generate_model types/volume <<- 'EOT'
Volume
VolumeCreateRequest
VolumeListResponse
VolumesDiskUsage
EOT
#endregion
#region -------- Operations --------
generate_operation --skip-responses --skip-parameters <<- 'EOT'
Authenticate
ImageHistory
EOT
#endregion

View File

@@ -0,0 +1,52 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
API_DIR="${SCRIPT_DIR}/.."
TMP_DIR="$(mktemp -d)"
trap "rm -rf ${TMP_DIR}" EXIT
GEN_FILES=()
echo "Validating generated code..."
echo "Separating generated files from handwritten files..."
while IFS= read -r file; do
GEN_FILES+=("$file")
done < <(grep -rl "// Code generated" "${API_DIR}/types" || true)
echo "Copying generated files into temporary folder..."
for f in "${GEN_FILES[@]}"; do
mkdir -p "${TMP_DIR}/$(dirname "${f#${API_DIR}/}")"
cp "$f" "${TMP_DIR}/${f#${API_DIR}/}"
done
cp "${API_DIR}/swagger.yaml" "${TMP_DIR}/"
cp "${API_DIR}/swagger-gen.yaml" "${TMP_DIR}/"
cp -r "${API_DIR}/templates" "${TMP_DIR}/" 2> /dev/null || true
echo "Generating swagger types in temporary folder..."
(
cd "${TMP_DIR}"
"${SCRIPT_DIR}/generate-swagger-api.sh" > /dev/null 2>&1
)
echo "Run diff for all generated files..."
DIFF_FOUND=false
for f in "${GEN_FILES[@]}"; do
REL="${f#${API_DIR}/}"
if ! diff -q "${TMP_DIR}/${REL}" "${API_DIR}/${REL}" > /dev/null 2>&1; then
echo "Difference found in ${REL}"
diff -u "${TMP_DIR}/${REL}" "${API_DIR}/${REL}" || true
DIFF_FOUND=true
fi
done
if [ "$DIFF_FOUND" = true ]; then
echo
echo "Swagger validation failed. Please run:"
echo " ./scripts/generate-swagger-api.sh"
echo "and commit updated generated files."
exit 1
fi
echo "Swagger file is up to date."

16
api/scripts/validate-swagger.sh Executable file
View File

@@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -e
# Expected to be in api directory
cd "$(dirname "${BASH_SOURCE[0]}")/.."
echo "Validating swagger.yaml..."
yamllint -f parsable -c validate/yamllint.yaml swagger.yaml
if out=$(swagger validate swagger.yaml); then
echo "Validation done! ${out}"
else
echo "${out}" >&2
false
fi

29
api/validate/yamllint Executable file
View File

@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -e
SCRIPTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPTDIR}/.validate"
if [ -n "${TEST_FORCE_VALIDATE:-}" ]; then
files=(docs/api/*.yaml)
else
IFS=$'\n'
files=($(validate_diff --diff-filter=ACMR --name-only -- docs/*.yaml || true))
unset IFS
fi
# validate the yamllint configuration file before anything else
if out=$(yamllint -f parsable -d "{extends: default, rules: {document-start: disable}}" "${SCRIPTDIR}"/yamllint.yaml); then
echo "Congratulations! yamllint config file formatted correctly"
else
echo "${out}" >&2
false
fi
# Then validate GitHub actions workflows, and conditionally lint the swagger
# files in the docs directory, as these are large files and take some time.
if out=$(yamllint -f parsable -c "${SCRIPTDIR}"/yamllint.yaml .github/workflows/*.yml "${files[@]}"); then
echo "Congratulations! YAML files are formatted correctly"
else
echo "${out}" >&2
false
fi

View File

@@ -0,0 +1,10 @@
extends: default
locale: C.UTF-8
rules:
document-start: disable
line-length: disable
# ignore "warning truthy value should be one of [false, true]" on GitHub
# actions workflows, which use "on:" to specify when to run.
truthy:
ignore: |
.github/workflows/