Skip to content

Commit 8e89765

Browse files
authored
Merge pull request #51 from ArthurFlag/ENGDOCS-2813-cli-docs
docs: add cli generator
2 parents c7daefb + 493d333 commit 8e89765

File tree

128 files changed

+13356
-4
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+13356
-4
lines changed

.dockerignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@
44
!/go.mod
55
!/go.sum
66
!/.golangci.yml
7-
!/vendor
7+
!/vendor
8+
!/docs
9+
!/.git

.github/workflows/validate.yml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: validate
2+
3+
permissions:
4+
contents: read
5+
6+
concurrency:
7+
group: ${{ github.workflow }}-${{ github.ref }}
8+
cancel-in-progress: true
9+
10+
on:
11+
workflow_dispatch:
12+
push:
13+
branches:
14+
- 'main'
15+
tags:
16+
- 'v*'
17+
pull_request:
18+
19+
jobs:
20+
prepare:
21+
runs-on: ubuntu-24.04
22+
outputs:
23+
targets: ${{ steps.generate.outputs.targets }}
24+
steps:
25+
-
26+
name: Checkout
27+
uses: actions/checkout@v4
28+
-
29+
name: List targets
30+
id: generate
31+
uses: docker/bake-action/subaction/list-targets@v6
32+
with:
33+
target: validate-docs
34+
35+
validate:
36+
runs-on: ubuntu-24.04
37+
needs:
38+
- prepare
39+
strategy:
40+
fail-fast: false
41+
matrix:
42+
target: ${{ fromJson(needs.prepare.outputs.targets) }}
43+
steps:
44+
-
45+
name: Set up Docker Buildx
46+
uses: docker/setup-buildx-action@v3
47+
with:
48+
buildkitd-flags: --debug
49+
-
50+
name: Validate
51+
uses: docker/bake-action@v6
52+
with:
53+
targets: ${{ matrix.target }}

Dockerfile

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,52 @@
11
#syntax=docker/dockerfile:1
22

33
ARG GO_VERSION=1.24.4
4+
ARG DOCS_FORMATS="md,yaml"
45

56
FROM --platform=${BUILDPLATFORM} golangci/golangci-lint:v2.1.6-alpine AS lint-base
67

78
FROM --platform=${BUILDPLATFORM} golang:${GO_VERSION}-alpine AS base
8-
RUN apk add --no-cache git
9+
RUN apk add --no-cache git rsync
910
WORKDIR /app
1011

12+
# Docs generation and validation targets
13+
FROM base AS docs-gen
14+
WORKDIR /src
15+
RUN --mount=target=. \
16+
--mount=target=/root/.cache,type=cache \
17+
go build -mod=vendor -o /out/docsgen ./docs/generator/generate.go
18+
19+
FROM base AS docs-build
20+
COPY --from=docs-gen /out/docsgen /usr/bin
21+
ENV DOCKER_CLI_PLUGIN_ORIGINAL_CLI_COMMAND="mcp"
22+
ARG DOCS_FORMATS
23+
RUN --mount=target=/context \
24+
--mount=target=.,type=tmpfs <<EOT
25+
set -e
26+
rsync -a /context/. .
27+
docsgen --formats "$DOCS_FORMATS" --source "docs/generator/reference"
28+
mkdir /out
29+
cp -r docs/generator/reference/* /out/
30+
EOT
31+
32+
FROM scratch AS docs-update
33+
COPY --from=docs-build /out /
34+
35+
FROM docs-build AS docs-validate
36+
RUN --mount=target=/context \
37+
--mount=target=.,type=tmpfs <<EOT
38+
set -e
39+
rsync -a /context/. .
40+
git add -A
41+
rm -rf docs/generator/reference/*
42+
cp -rf /out/* ./docs/generator/reference/
43+
if [ -n "$(git status --porcelain -- docs/generator/reference)" ]; then
44+
echo >&2 'ERROR: Docs result differs. Rebase on main branch and rerun "make docs"'
45+
git status --porcelain -- docs/generator/reference
46+
exit 1
47+
fi
48+
EOT
49+
1150
FROM base AS lint
1251
COPY --from=lint-base /usr/bin/golangci-lint /usr/bin/golangci-lint
1352
ARG TARGETOS

Makefile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ docker-mcp-cross:
3434
docker-mcp-%:
3535
docker buildx build $(DOCKER_BUILD_ARGS) --target=package-docker-mcp --platform=$*/amd64,$*/arm64 -o ./dist .
3636

37+
docs:
38+
$(eval $@_TMP_OUT := $(shell mktemp -d -t mcp-cli-output.XXXXXXXXXX))
39+
docker buildx bake --set "*.output=type=local,dest=$($@_TMP_OUT)" update-docs
40+
rm -rf ./docs/generator/reference/*
41+
cp -R "$($@_TMP_OUT)"/* ./docs/generator/reference/
42+
rm -rf "$($@_TMP_OUT)"/*
43+
3744
push-module-image:
3845
cp -r dist ./module-image
3946
docker buildx build --push --platform=linux/amd64,linux/arm64,darwin/amd64,darwin/arm64,windows/amd64,windows/arm64 --build-arg TAG=$(TAG) --tag=docker/docker-mcp-cli-desktop-module:$(TAG) ./module-image
@@ -70,4 +77,4 @@ push-l7proxy-image:
7077
push-dns-forwarder-image:
7178
docker buildx bake dns-forwarder --push
7279

73-
.PHONY: format lint clean docker-mcp-cross push-module-image mcp-package test docker-mcp push-mcp-gateway push-l4proxy-image push-l7proxy-image push-dns-forwarder-image
80+
.PHONY: format lint clean docker-mcp-cross push-module-image mcp-package test docker-mcp push-mcp-gateway push-l4proxy-image push-l7proxy-image push-dns-forwarder-image docs

docker-bake.hcl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
variable "GO_VERSION" {
2+
default = null
3+
}
4+
5+
target "_common" {
6+
args = {
7+
GO_VERSION = GO_VERSION
8+
BUILDKIT_CONTEXT_KEEP_GIT_DIR = 1
9+
}
10+
}
11+
12+
variable "DOCS_FORMATS" {
13+
default = "md,yaml"
14+
}
115

216
group default {
317
targets = [
@@ -13,6 +27,7 @@ group all {
1327
"l4proxy",
1428
"l7proxy",
1529
"dns-forwarder",
30+
"validate-docs",
1631
]
1732
}
1833

@@ -76,4 +91,22 @@ target mcp-gateway-dind {
7691
output = [
7792
"type=image,name=docker/mcp-gateway:dind",
7893
]
94+
}
95+
96+
target "validate-docs" {
97+
inherits = ["_common"]
98+
args = {
99+
DOCS_FORMATS = DOCS_FORMATS
100+
}
101+
target = "docs-validate"
102+
output = ["type=cacheonly"]
103+
}
104+
105+
target "update-docs" {
106+
inherits = ["_common"]
107+
args = {
108+
DOCS_FORMATS = DOCS_FORMATS
109+
}
110+
target = "docs-update"
111+
output = ["./docs/generator/reference"]
79112
}

docs/generator/generate.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"log"
6+
"os"
7+
"strings"
8+
9+
clidocstool "github.com/docker/cli-docs-tool"
10+
"github.com/docker/cli/cli/command"
11+
"github.com/pkg/errors"
12+
"github.com/spf13/cobra"
13+
"github.com/spf13/pflag"
14+
15+
"github.com/docker/mcp-gateway/cmd/docker-mcp/commands"
16+
)
17+
18+
const defaultSourcePath = "/reference/"
19+
20+
type options struct {
21+
source string
22+
formats []string
23+
}
24+
25+
func gen(opts *options) error {
26+
log.SetFlags(0)
27+
28+
dockerCLI, err := command.NewDockerCli()
29+
if err != nil {
30+
return err
31+
}
32+
cmd := &cobra.Command{
33+
Use: "docker [OPTIONS] COMMAND [ARG...]",
34+
Short: "The base command for the Docker CLI.",
35+
DisableAutoGenTag: true,
36+
}
37+
38+
cmd.AddCommand(commands.Root(context.TODO(), "", dockerCLI))
39+
40+
c, err := clidocstool.New(clidocstool.Options{
41+
Root: cmd,
42+
SourceDir: opts.source,
43+
Plugin: true,
44+
})
45+
if err != nil {
46+
return err
47+
}
48+
49+
for _, format := range opts.formats {
50+
switch format {
51+
case "md":
52+
if err = c.GenMarkdownTree(cmd); err != nil {
53+
return err
54+
}
55+
case "yaml":
56+
fixUpExperimentalCLI(cmd)
57+
if err = c.GenYamlTree(cmd); err != nil {
58+
return err
59+
}
60+
default:
61+
return errors.Errorf("unknown format %q", format)
62+
}
63+
}
64+
65+
return nil
66+
}
67+
68+
func run() error {
69+
opts := &options{}
70+
flags := pflag.NewFlagSet(os.Args[0], pflag.ContinueOnError)
71+
flags.StringVar(&opts.source, "source", defaultSourcePath, "Docs source folder")
72+
flags.StringSliceVar(&opts.formats, "formats", []string{}, "Format (md, yaml)")
73+
if err := flags.Parse(os.Args[1:]); err != nil {
74+
return err
75+
}
76+
if len(opts.formats) == 0 {
77+
return errors.New("Docs format required")
78+
}
79+
return gen(opts)
80+
}
81+
82+
func main() {
83+
if err := run(); err != nil {
84+
log.Printf("ERROR: %+v", err)
85+
os.Exit(1)
86+
}
87+
}
88+
89+
// fixUpExperimentalCLI trims the " (EXPERIMENTAL)" suffix from the CLI output,
90+
// as docs.docker.com already displays "experimental (CLI)",
91+
//
92+
// https://github.com/docker/buildx/pull/2188#issuecomment-1889487022
93+
func fixUpExperimentalCLI(cmd *cobra.Command) {
94+
const (
95+
annotationExperimentalCLI = "experimentalCLI"
96+
suffixExperimental = " (EXPERIMENTAL)"
97+
)
98+
if _, ok := cmd.Annotations[annotationExperimentalCLI]; ok {
99+
cmd.Short = strings.TrimSuffix(cmd.Short, suffixExperimental)
100+
}
101+
cmd.Flags().VisitAll(func(f *pflag.Flag) {
102+
if _, ok := f.Annotations[annotationExperimentalCLI]; ok {
103+
f.Usage = strings.TrimSuffix(f.Usage, suffixExperimental)
104+
}
105+
})
106+
for _, c := range cmd.Commands() {
107+
fixUpExperimentalCLI(c)
108+
}
109+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
command: docker mcp
2+
pname: docker
3+
plink: docker.yaml
4+
cname:
5+
- docker mcp catalog
6+
- docker mcp client
7+
- docker mcp config
8+
- docker mcp gateway
9+
- docker mcp policy
10+
- docker mcp secret
11+
- docker mcp server
12+
- docker mcp tools
13+
- docker mcp version
14+
clink:
15+
- docker_mcp_catalog.yaml
16+
- docker_mcp_client.yaml
17+
- docker_mcp_config.yaml
18+
- docker_mcp_gateway.yaml
19+
- docker_mcp_policy.yaml
20+
- docker_mcp_secret.yaml
21+
- docker_mcp_server.yaml
22+
- docker_mcp_tools.yaml
23+
- docker_mcp_version.yaml
24+
options:
25+
- option: version
26+
shorthand: v
27+
value_type: bool
28+
default_value: "false"
29+
description: Print version information and quit
30+
deprecated: false
31+
hidden: false
32+
experimental: false
33+
experimentalcli: false
34+
kubernetes: false
35+
swarm: false
36+
deprecated: false
37+
hidden: false
38+
experimental: false
39+
experimentalcli: false
40+
kubernetes: false
41+
swarm: false
42+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
command: docker mcp catalog
2+
aliases: docker mcp catalog, docker mcp catalogs
3+
short: Manage the catalog
4+
long: Manage the catalog
5+
pname: docker mcp
6+
plink: docker_mcp.yaml
7+
cname:
8+
- docker mcp catalog init
9+
- docker mcp catalog ls
10+
- docker mcp catalog reset
11+
- docker mcp catalog show
12+
- docker mcp catalog update
13+
clink:
14+
- docker_mcp_catalog_init.yaml
15+
- docker_mcp_catalog_ls.yaml
16+
- docker_mcp_catalog_reset.yaml
17+
- docker_mcp_catalog_show.yaml
18+
- docker_mcp_catalog_update.yaml
19+
deprecated: false
20+
hidden: false
21+
experimental: false
22+
experimentalcli: false
23+
kubernetes: false
24+
swarm: false
25+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
command: docker mcp catalog add
2+
short: Add a server to your catalog
3+
long: Add a server to your catalog
4+
usage: docker mcp catalog add <catalog> <server-name> <catalog-file>
5+
pname: docker mcp catalog
6+
plink: docker_mcp_catalog.yaml
7+
options:
8+
- option: force
9+
value_type: bool
10+
default_value: "false"
11+
description: Overwrite existing server in the catalog
12+
deprecated: false
13+
hidden: false
14+
experimental: false
15+
experimentalcli: false
16+
kubernetes: false
17+
swarm: false
18+
deprecated: false
19+
hidden: true
20+
experimental: false
21+
experimentalcli: false
22+
kubernetes: false
23+
swarm: false
24+

0 commit comments

Comments
 (0)