Skip to content

build: Build-metadata usage via go:embed #689

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
.github
.vscode
script
third-party
.dockerignore
.gitignore
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: Build and Test Go Project
on: [push, pull_request]
on: [ push, pull_request ]

permissions:
contents: read
Expand All @@ -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 }}

Expand All @@ -28,5 +28,8 @@ jobs:
- name: Run unit tests
run: script/test

- name: Prepare build_info files
run: script/prepare-build-info

- name: Build
run: go build -v ./cmd/github-mcp-server
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.idea
cmd/github-mcp-server/github-mcp-server
cmd/github-mcp-server/build_info/*.txt

# VSCode
.vscode/*
Expand Down
6 changes: 5 additions & 1 deletion .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
},
Expand All @@ -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",
}
Expand Down
8 changes: 4 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
FROM golang:1.24.4-alpine AS build
ARG VERSION="dev"

# Set the working directory
WORKDIR /build
Expand All @@ -12,9 +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=. \
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)" \
-o /bin/github-mcp-server cmd/github-mcp-server/main.go
--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

# Make a stage to run the app
FROM gcr.io/distroless/base-debian12
Expand Down
35 changes: 35 additions & 0 deletions cmd/github-mcp-server/build_info.go
Original file line number Diff line number Diff line change
@@ -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"),
}
}()
1 change: 1 addition & 0 deletions cmd/github-mcp-server/build_info/commit.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
commit
1 change: 1 addition & 0 deletions cmd/github-mcp-server/build_info/date.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
date
1 change: 1 addition & 0 deletions cmd/github-mcp-server/build_info/version.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
version
43 changes: 43 additions & 0 deletions cmd/github-mcp-server/build_info_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
9 changes: 2 additions & 7 deletions cmd/github-mcp-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand All @@ -46,7 +41,7 @@ var (
}

stdioServerConfig := ghmcp.StdioServerConfig{
Version: version,
Version: buildInfo.version,
Host: viper.GetString("host"),
Token: token,
EnabledToolsets: enabledToolsets,
Expand Down
14 changes: 14 additions & 0 deletions cmd/github-mcp-server/main_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
5 changes: 2 additions & 3 deletions script/get-discussions
Original file line number Diff line number Diff line change
@@ -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 .
2 changes: 1 addition & 1 deletion script/get-me
Original file line number Diff line number Diff line change
@@ -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 .
29 changes: 29 additions & 0 deletions script/prepare-build-info
Original file line number Diff line number Diff line change
@@ -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 commit')
VERSION=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo 'unknown version')
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