From 8512cc34c1a74d7fc7cd552bda7625d4f27bdf18 Mon Sep 17 00:00:00 2001 From: Markus Schulte Date: Wed, 16 Jul 2025 20:21:17 +0200 Subject: [PATCH 1/4] build: Build-metadata usage via go:embed Refactor build metadata injection logic: - Introduced `build_info` package to manage version, commit, and date details. - Removed ldflags-based metadata injection. - Updated workflows and Dockerfile to prepare `build_info` files. - Added unit tests for `build_info` initialization and formatting. Because: Since build-metadata no longer needs compiling to binary, this information can already be defined at the source code level. Related #630 --- .github/workflows/go.yml | 16 +++++++- .goreleaser.yaml | 6 ++- Dockerfile | 9 +++- cmd/github-mcp-server/build_info.go | 35 ++++++++++++++++ cmd/github-mcp-server/build_info/commit.txt | 1 + cmd/github-mcp-server/build_info/date.txt | 1 + cmd/github-mcp-server/build_info/version.txt | 1 + cmd/github-mcp-server/build_info_test.go | 43 ++++++++++++++++++++ cmd/github-mcp-server/main.go | 9 +--- cmd/github-mcp-server/main_test.go | 14 +++++++ 10 files changed, 124 insertions(+), 11 deletions(-) create mode 100644 cmd/github-mcp-server/build_info.go create mode 100644 cmd/github-mcp-server/build_info/commit.txt create mode 100644 cmd/github-mcp-server/build_info/date.txt create mode 100644 cmd/github-mcp-server/build_info/version.txt create mode 100644 cmd/github-mcp-server/build_info_test.go create mode 100644 cmd/github-mcp-server/main_test.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index e3ef25022..512884798 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -1,5 +1,5 @@ name: Build and Test Go Project -on: [push, pull_request] +on: [ push, pull_request ] permissions: contents: read @@ -9,7 +9,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-latest] + os: [ ubuntu-latest, windows-latest, macos-latest ] runs-on: ${{ matrix.os }} @@ -28,5 +28,17 @@ jobs: - name: Run unit tests run: script/test + - name: Prepare build_info files + shell: bash + run: | + BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ) + mkdir -p cmd/github-mcp-server/build_info + echo "${{ github.sha }}" > cmd/github-mcp-server/build_info/commit.txt + echo "$BUILD_DATE" > cmd/github-mcp-server/build_info/date.txt + if [ "${{ github.event_name }}" = "push" ]; then + echo "${{ github.ref_name }}" > cmd/github-mcp-server/build_info/version.txt + else + echo "pr-${{ github.event.pull_request.number }}" > cmd/github-mcp-server/build_info/version.txt + fi - name: Build run: go build -v ./cmd/github-mcp-server diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 54f6b9f40..0cbbd1439 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -4,12 +4,16 @@ before: hooks: - go mod tidy - go generate ./... + - mkdir -p cmd/github-mcp-server/build_info + - echo "{{.Commit}}" > cmd/github-mcp-server/build_info/commit.txt + - echo "{{.Date}}" > cmd/github-mcp-server/build_info/date.txt + - echo "{{.Version}}" > cmd/github-mcp-server/build_info/version.txt builds: - env: - CGO_ENABLED=0 ldflags: - - -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} + - -s -w goos: - linux - windows diff --git a/Dockerfile b/Dockerfile index a26f19a81..220e180a4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,12 +8,19 @@ WORKDIR /build RUN --mount=type=cache,target=/var/cache/apk \ apk add git +# Prepare build_info files +RUN --mount=type=bind,target=. \ + mkdir -p cmd/github-mcp-server/build_info && \ + git rev-parse HEAD > cmd/github-mcp-server/build_info/commit.txt && \ + date -u +%Y-%m-%dT%H:%M:%SZ > cmd/github-mcp-server/build_info/date.txt && \ + echo "${VERSION}" > cmd/github-mcp-server/build_info/version.txt + # Build the server # go build automatically download required module dependencies to /go/pkg/mod RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ --mount=type=bind,target=. \ - CGO_ENABLED=0 go build -ldflags="-s -w -X main.version=${VERSION} -X main.commit=$(git rev-parse HEAD) -X main.date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ + CGO_ENABLED=0 go build -ldflags="-s -w" \ -o /bin/github-mcp-server cmd/github-mcp-server/main.go # Make a stage to run the app diff --git a/cmd/github-mcp-server/build_info.go b/cmd/github-mcp-server/build_info.go new file mode 100644 index 000000000..32bbed3bc --- /dev/null +++ b/cmd/github-mcp-server/build_info.go @@ -0,0 +1,35 @@ +package main + +import ( + "embed" + "fmt" + "strings" +) + +//go:embed build_info/commit.txt build_info/date.txt build_info/version.txt +var versionFS embed.FS + +type buildInfoStruct struct { + commit string + date string + version string +} + +func (b buildInfoStruct) String() string { + return fmt.Sprintf("Commit: %s\nBuild Date: %s\nVersion: %s", b.commit, b.date, b.version) +} + +var buildInfo = func() buildInfoStruct { + readFile := func(path, fallback string) string { + if content, err := versionFS.ReadFile(path); err == nil { + return strings.TrimSpace(string(content)) + } + return fallback + } + + return buildInfoStruct{ + commit: readFile("build_info/commit.txt", "unknown commit"), + date: readFile("build_info/date.txt", "unknown date"), + version: readFile("build_info/version.txt", "unknown version"), + } +}() diff --git a/cmd/github-mcp-server/build_info/commit.txt b/cmd/github-mcp-server/build_info/commit.txt new file mode 100644 index 000000000..fcad76582 --- /dev/null +++ b/cmd/github-mcp-server/build_info/commit.txt @@ -0,0 +1 @@ +commit \ No newline at end of file diff --git a/cmd/github-mcp-server/build_info/date.txt b/cmd/github-mcp-server/build_info/date.txt new file mode 100644 index 000000000..81229b4a8 --- /dev/null +++ b/cmd/github-mcp-server/build_info/date.txt @@ -0,0 +1 @@ +date \ No newline at end of file diff --git a/cmd/github-mcp-server/build_info/version.txt b/cmd/github-mcp-server/build_info/version.txt new file mode 100644 index 000000000..ca291e965 --- /dev/null +++ b/cmd/github-mcp-server/build_info/version.txt @@ -0,0 +1 @@ +version \ No newline at end of file diff --git a/cmd/github-mcp-server/build_info_test.go b/cmd/github-mcp-server/build_info_test.go new file mode 100644 index 000000000..7d3ac522e --- /dev/null +++ b/cmd/github-mcp-server/build_info_test.go @@ -0,0 +1,43 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBuildInfoStruct_String(t *testing.T) { + tests := []struct { + name string + info buildInfoStruct + expected string + }{ + { + name: "all fields populated", + info: buildInfoStruct{ + commit: "abc123", + date: "2024-01-01", + version: "1.0.0", + }, + expected: "Commit: abc123\nBuild Date: 2024-01-01\nVersion: 1.0.0", + }, + { + name: "initialized struct", + info: buildInfoStruct{}, + expected: "Commit: \nBuild Date: \nVersion: ", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := tt.info.String() + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestBuildInfo_Initialization(t *testing.T) { + assert.Equal(t, "commit", buildInfo.commit) + assert.Equal(t, "date", buildInfo.date) + assert.Equal(t, "version", buildInfo.version) +} diff --git a/cmd/github-mcp-server/main.go b/cmd/github-mcp-server/main.go index cad002666..9210926ba 100644 --- a/cmd/github-mcp-server/main.go +++ b/cmd/github-mcp-server/main.go @@ -13,17 +13,12 @@ import ( "github.com/spf13/viper" ) -// These variables are set by the build process using ldflags. -var version = "version" -var commit = "commit" -var date = "date" - var ( rootCmd = &cobra.Command{ Use: "server", Short: "GitHub MCP Server", Long: `A GitHub MCP server that handles various tools and resources.`, - Version: fmt.Sprintf("Version: %s\nCommit: %s\nBuild Date: %s", version, commit, date), + Version: buildInfo.String(), } stdioCmd = &cobra.Command{ @@ -46,7 +41,7 @@ var ( } stdioServerConfig := ghmcp.StdioServerConfig{ - Version: version, + Version: buildInfo.version, Host: viper.GetString("host"), Token: token, EnabledToolsets: enabledToolsets, diff --git a/cmd/github-mcp-server/main_test.go b/cmd/github-mcp-server/main_test.go new file mode 100644 index 000000000..80f2fe231 --- /dev/null +++ b/cmd/github-mcp-server/main_test.go @@ -0,0 +1,14 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_RootCmdVersion(t *testing.T) { + expectedVersion := buildInfo.String() + actualVersion := rootCmd.Version + + assert.Equal(t, expectedVersion, actualVersion) +} From 470a37461682c66c225d11a7761a7e4aa6522475 Mon Sep 17 00:00:00 2001 From: Markus Schulte Date: Thu, 17 Jul 2025 11:07:03 +0200 Subject: [PATCH 2/4] build: move build metadata preparation to a standalone script - Extracted `build_info` preparation logic to `script/prepare-build-info`. - Updated Dockerfile and GitHub workflows to use the new script. - Simplified metadata injection process for better reusability. --- .github/workflows/go.yml | 13 ++----------- Dockerfile | 9 +-------- script/prepare-build-info | 29 +++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 19 deletions(-) create mode 100755 script/prepare-build-info diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 512884798..38e8904a3 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -29,16 +29,7 @@ jobs: run: script/test - name: Prepare build_info files - shell: bash - run: | - BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ) - mkdir -p cmd/github-mcp-server/build_info - echo "${{ github.sha }}" > cmd/github-mcp-server/build_info/commit.txt - echo "$BUILD_DATE" > cmd/github-mcp-server/build_info/date.txt - if [ "${{ github.event_name }}" = "push" ]; then - echo "${{ github.ref_name }}" > cmd/github-mcp-server/build_info/version.txt - else - echo "pr-${{ github.event.pull_request.number }}" > cmd/github-mcp-server/build_info/version.txt - fi + run: script/prepare-build-info + - name: Build run: go build -v ./cmd/github-mcp-server diff --git a/Dockerfile b/Dockerfile index 220e180a4..0b5b0effd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,4 @@ FROM golang:1.24.4-alpine AS build -ARG VERSION="dev" # Set the working directory WORKDIR /build @@ -8,18 +7,12 @@ WORKDIR /build RUN --mount=type=cache,target=/var/cache/apk \ apk add git -# Prepare build_info files -RUN --mount=type=bind,target=. \ - mkdir -p cmd/github-mcp-server/build_info && \ - git rev-parse HEAD > cmd/github-mcp-server/build_info/commit.txt && \ - date -u +%Y-%m-%dT%H:%M:%SZ > cmd/github-mcp-server/build_info/date.txt && \ - echo "${VERSION}" > cmd/github-mcp-server/build_info/version.txt - # Build the server # go build automatically download required module dependencies to /go/pkg/mod RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ --mount=type=bind,target=. \ + script/prepare-build-info && \ CGO_ENABLED=0 go build -ldflags="-s -w" \ -o /bin/github-mcp-server cmd/github-mcp-server/main.go diff --git a/script/prepare-build-info b/script/prepare-build-info new file mode 100755 index 000000000..35bc99c28 --- /dev/null +++ b/script/prepare-build-info @@ -0,0 +1,29 @@ + +#!/bin/sh +set -eu + +mkdir -p cmd/github-mcp-server/build_info + +BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ) + +if [ -n "${GITHUB_ACTIONS:-}" ]; then + # GitHub Actions context + COMMIT="${GITHUB_SHA}" + + if [ "${GITHUB_EVENT_NAME}" = "push" ] && [ "${GITHUB_REF_TYPE}" = "tag" ]; then + VERSION="${GITHUB_REF_NAME}" + elif [ "${GITHUB_EVENT_NAME}" = "push" ]; then + VERSION="${GITHUB_REF_NAME}-${GITHUB_SHA}" + else + VERSION="pr-${GITHUB_EVENT_PULL_REQUEST_NUMBER}" + fi +else + # Local/Docker context + COMMIT=$(git rev-parse HEAD 2>/dev/null || echo 'unknown') + VERSION="dev" +fi + +# Write build info files +echo "${COMMIT}" > cmd/github-mcp-server/build_info/commit.txt +echo "${BUILD_DATE}" > cmd/github-mcp-server/build_info/date.txt +echo "${VERSION}" > cmd/github-mcp-server/build_info/version.txt \ No newline at end of file From fd28c206018f34cd46d234d7c5de3e0648ad4311 Mon Sep 17 00:00:00 2001 From: Markus Schulte Date: Thu, 17 Jul 2025 11:37:29 +0200 Subject: [PATCH 3/4] build: simplify command references and update build info generation - Replaced direct file paths with relative command paths in scripts and config files for consistency. - Enhanced build info generation with improved handling of commit and branch information. - Updated `.gitignore` to include dynamic build info files. - Enabled write access in Dockerfile bind mount to align with changes. --- .dockerignore | 1 - .gitignore | 4 ++-- .vscode/launch.json | 4 ++-- Dockerfile | 4 ++-- script/get-discussions | 5 ++--- script/get-me | 2 +- script/prepare-build-info | 4 ++-- 7 files changed, 11 insertions(+), 13 deletions(-) diff --git a/.dockerignore b/.dockerignore index 8f302e7c0..c5248351d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,5 @@ .github .vscode -script third-party .dockerignore .gitignore diff --git a/.gitignore b/.gitignore index 0ad709cbf..13e0f128e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -.idea -cmd/github-mcp-server/github-mcp-server +.idea/ +cmd/github-mcp-server/build_info/*.txt # VSCode .vscode/* diff --git a/.vscode/launch.json b/.vscode/launch.json index cea7fd917..2941bf846 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,7 @@ "request": "launch", "mode": "auto", "cwd": "${workspaceFolder}", - "program": "cmd/github-mcp-server/main.go", + "program": "./cmd/github-mcp-server", "args": ["stdio"], "console": "integratedTerminal", }, @@ -20,7 +20,7 @@ "request": "launch", "mode": "auto", "cwd": "${workspaceFolder}", - "program": "cmd/github-mcp-server/main.go", + "program": "./cmd/github-mcp-server", "args": ["stdio", "--read-only"], "console": "integratedTerminal", } diff --git a/Dockerfile b/Dockerfile index 0b5b0effd..0384df249 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,10 +11,10 @@ RUN --mount=type=cache,target=/var/cache/apk \ # go build automatically download required module dependencies to /go/pkg/mod RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ - --mount=type=bind,target=. \ + --mount=type=bind,target=.,rw \ script/prepare-build-info && \ CGO_ENABLED=0 go build -ldflags="-s -w" \ - -o /bin/github-mcp-server cmd/github-mcp-server/main.go + -o /bin/github-mcp-server ./cmd/github-mcp-server # Make a stage to run the app FROM gcr.io/distroless/base-debian12 diff --git a/script/get-discussions b/script/get-discussions index 3e68abf24..5183c8b24 100755 --- a/script/get-discussions +++ b/script/get-discussions @@ -1,5 +1,4 @@ #!/bin/bash -# echo '{"jsonrpc":"2.0","id":3,"params":{"name":"list_discussions","arguments": {"owner": "github", "repo": "securitylab", "first": 10, "since": "2025-04-01T00:00:00Z"}},"method":"tools/call"}' | go run cmd/github-mcp-server/main.go stdio | jq . -echo '{"jsonrpc":"2.0","id":3,"params":{"name":"list_discussions","arguments": {"owner": "github", "repo": "securitylab", "first": 10, "since": "2025-04-01T00:00:00Z", "sort": "CREATED_AT", "direction": "DESC"}},"method":"tools/call"}' | go run cmd/github-mcp-server/main.go stdio | jq . - +# echo '{"jsonrpc":"2.0","id":3,"params":{"name":"list_discussions","arguments": {"owner": "github", "repo": "securitylab", "first": 10, "since": "2025-04-01T00:00:00Z"}},"method":"tools/call"}' | go run ./cmd/github-mcp-server stdio | jq . +echo '{"jsonrpc":"2.0","id":3,"params":{"name":"list_discussions","arguments": {"owner": "github", "repo": "securitylab", "first": 10, "since": "2025-04-01T00:00:00Z", "sort": "CREATED_AT", "direction": "DESC"}},"method":"tools/call"}' | go run ./cmd/github-mcp-server stdio | jq . diff --git a/script/get-me b/script/get-me index 46339ae53..425713af6 100755 --- a/script/get-me +++ b/script/get-me @@ -1,3 +1,3 @@ #!/bin/bash -echo '{"jsonrpc":"2.0","id":3,"params":{"name":"get_me"},"method":"tools/call"}' | go run cmd/github-mcp-server/main.go stdio | jq . +echo '{"jsonrpc":"2.0","id":3,"params":{"name":"get_me"},"method":"tools/call"}' | go run ./cmd/github-mcp-server stdio | jq . diff --git a/script/prepare-build-info b/script/prepare-build-info index 35bc99c28..d82b65f1c 100755 --- a/script/prepare-build-info +++ b/script/prepare-build-info @@ -19,8 +19,8 @@ if [ -n "${GITHUB_ACTIONS:-}" ]; then fi else # Local/Docker context - COMMIT=$(git rev-parse HEAD 2>/dev/null || echo 'unknown') - VERSION="dev" + COMMIT=$(git rev-parse HEAD 2>/dev/null || echo 'unknown commit') + VERSION=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo 'unknown version') fi # Write build info files From 2ab52b9b009729fe020c4e980365f2540bb5dc60 Mon Sep 17 00:00:00 2001 From: Markus Schulte Date: Thu, 17 Jul 2025 13:02:24 +0200 Subject: [PATCH 4/4] build: update `.gitignore` to include binary and adjust `.idea` entry --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 13e0f128e..e11e0d2c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ -.idea/ +.idea +cmd/github-mcp-server/github-mcp-server cmd/github-mcp-server/build_info/*.txt # VSCode