Skip to content

Commit c96145b

Browse files
committed
fix: update release process
1 parent 1f4ed4e commit c96145b

11 files changed

Lines changed: 234 additions & 149 deletions

File tree

.github/workflows/release.yml

Lines changed: 161 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,45 +16,190 @@ on:
1616
type: boolean
1717

1818
jobs:
19-
create-release:
19+
validate-release:
2020
runs-on: ubuntu-latest
2121
outputs:
22-
MAJOR: ${{ steps.version.outputs.MAJOR }}
23-
MINOR: ${{ steps.version.outputs.MINOR }}
24-
PATCH: ${{ steps.version.outputs.PATCH }}
22+
major: ${{ steps.extract-version.outputs.major }}
23+
minor: ${{ steps.extract-version.outputs.minor }}
24+
patch: ${{ steps.extract-version.outputs.patch }}
2525
steps:
2626
- name: Checkout code
2727
uses: actions/checkout@v4
2828

29-
- name: Extract version components
30-
id: version
29+
- name: Validate version format and extract components
30+
id: extract-version
3131
run: |
3232
VERSION="${{ github.event.inputs.version }}"
33+
34+
# Validate format (must be vX.Y.Z)
3335
if [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
34-
echo "Invalid version format. Must be vX.Y.Z"
36+
echo "::error::Invalid version format. Must be vX.Y.Z (e.g., v0.1.0)"
3537
exit 1
3638
fi
39+
40+
# Extract components
3741
VERSION_NUM="${VERSION#v}"
3842
IFS=. read -r MAJOR MINOR PATCH <<< "$VERSION_NUM"
39-
echo "MAJOR=$MAJOR" >> $GITHUB_OUTPUT
40-
echo "MINOR=$MINOR" >> $GITHUB_OUTPUT
41-
echo "PATCH=$PATCH" >> $GITHUB_OUTPUT
42-
echo "VERSION_MAJOR=$MAJOR" >> $GITHUB_ENV
43-
echo "VERSION_MINOR=$MINOR" >> $GITHUB_ENV
44-
echo "VERSION_PATCH=$PATCH" >> $GITHUB_ENV
45-
echo "VERSION_BUILD=${{ github.run_number }}" >> $GITHUB_ENV
43+
44+
echo "major=$MAJOR" >> $GITHUB_OUTPUT
45+
echo "minor=$MINOR" >> $GITHUB_OUTPUT
46+
echo "patch=$PATCH" >> $GITHUB_OUTPUT
47+
48+
- name: Extract and validate source code version
49+
run: |
50+
# Parse version from pkg/config/env.go
51+
MAJOR=$(grep -E '^\s*VersionMajor\s*=\s*"[0-9]+"' pkg/config/env.go | sed -E 's/.*"([0-9]+)".*/\1/')
52+
MINOR=$(grep -E '^\s*VersionMinor\s*=\s*"[0-9]+"' pkg/config/env.go | sed -E 's/.*"([0-9]+)".*/\1/')
53+
PATCH=$(grep -E '^\s*VersionPatch\s*=\s*"[0-9]+"' pkg/config/env.go | sed -E 's/.*"([0-9]+)".*/\1/')
54+
55+
if [ -z "$MAJOR" ] || [ -z "$MINOR" ] || [ -z "$PATCH" ]; then
56+
echo "::error::Failed to extract version from pkg/config/env.go"
57+
exit 1
58+
fi
59+
60+
SOURCE_VERSION="$MAJOR.$MINOR.$PATCH"
61+
INPUT_VERSION="${{ steps.extract-version.outputs.major }}.${{ steps.extract-version.outputs.minor }}.${{ steps.extract-version.outputs.patch }}"
62+
63+
echo "Workflow input version: $INPUT_VERSION"
64+
echo "Source code version: $SOURCE_VERSION"
65+
66+
if [ "$INPUT_VERSION" != "$SOURCE_VERSION" ]; then
67+
echo "::error::Version mismatch!"
68+
echo "::error::Workflow input: v$INPUT_VERSION"
69+
echo "::error::Source code (pkg/config/env.go): $SOURCE_VERSION"
70+
echo "::error::Please update VersionMajor, VersionMinor, VersionPatch in pkg/config/env.go before releasing."
71+
exit 1
72+
fi
73+
74+
echo "✓ Version validation passed: $SOURCE_VERSION"
75+
76+
- name: Set up Go
77+
uses: actions/setup-go@v5
78+
with:
79+
go-version: "1.24"
80+
81+
- name: Install Task
82+
uses: go-task/setup-task@v1
83+
84+
- name: Run unit tests
85+
run: |
86+
echo "Running unit tests..."
87+
task test-unit
88+
echo "✓ Unit tests passed"
89+
90+
- name: Build release binary
91+
run: |
92+
echo "Building release binary..."
93+
task build-release
94+
95+
if [ ! -f mbvpn ]; then
96+
echo "::error::Build failed - mbvpn binary not found"
97+
exit 1
98+
fi
99+
100+
echo "✓ Build successful"
101+
102+
- name: Validate binary version output
103+
run: |
104+
echo "Testing binary version output..."
105+
106+
# Execute version command and capture output
107+
BINARY_OUTPUT=$(./mbvpn version)
108+
109+
# Expected output is single line: v0.0.9
110+
EXPECTED_VERSION="${{ github.event.inputs.version }}"
111+
112+
# Trim any whitespace
113+
BINARY_OUTPUT=$(echo "$BINARY_OUTPUT" | tr -d '[:space:]')
114+
EXPECTED_VERSION=$(echo "$EXPECTED_VERSION" | tr -d '[:space:]')
115+
116+
echo "Binary output: $BINARY_OUTPUT"
117+
echo "Expected version: $EXPECTED_VERSION"
118+
119+
if [ "$BINARY_OUTPUT" != "$EXPECTED_VERSION" ]; then
120+
echo "::error::Binary version mismatch!"
121+
echo "::error::Expected: $EXPECTED_VERSION"
122+
echo "::error::Got: $BINARY_OUTPUT"
123+
exit 1
124+
fi
125+
126+
echo "✓ Binary version validation passed"
127+
128+
- name: Validation summary
129+
run: |
130+
echo "======================================"
131+
echo "Release Validation Summary"
132+
echo "======================================"
133+
echo "✓ Version format validated"
134+
echo "✓ Source code version matches input"
135+
echo "✓ Unit tests passed"
136+
echo "✓ Build successful"
137+
echo "✓ Binary version output validated"
138+
echo ""
139+
echo "Version: ${{ github.event.inputs.version }}"
140+
echo "Ready to create release"
141+
echo "======================================"
142+
143+
create-release:
144+
needs: validate-release
145+
runs-on: ubuntu-latest
146+
outputs:
147+
MAJOR: ${{ needs.validate-release.outputs.major }}
148+
MINOR: ${{ needs.validate-release.outputs.minor }}
149+
PATCH: ${{ needs.validate-release.outputs.patch }}
150+
steps:
151+
- name: Checkout code
152+
uses: actions/checkout@v4
153+
154+
- name: Generate Release Notes
155+
id: release-notes
156+
run: |
157+
VERSION="${{ github.event.inputs.version }}"
158+
159+
# Get the previous tag
160+
PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
161+
162+
# Start building release notes
163+
cat > release_notes.md << 'EOF'
164+
## What's Changed
165+
166+
EOF
167+
168+
# If we have a previous tag, generate changelog
169+
if [ -n "$PREVIOUS_TAG" ]; then
170+
# Add commit range link
171+
echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREVIOUS_TAG}...${VERSION}" >> release_notes.md
172+
echo "" >> release_notes.md
173+
174+
# Get commits since last tag
175+
git log ${PREVIOUS_TAG}..HEAD --pretty=format:"* %s by @%an in %H" --no-merges > commits.txt
176+
177+
# Extract issue references and create proper links
178+
while IFS= read -r line; do
179+
# Replace commit hash with link
180+
line=$(echo "$line" | sed -E "s/ in ([0-9a-f]{40})/ in [\1](https:\/\/github.com\/${{ github.repository }}\/commit\/\1)/")
181+
# Replace issue references with links
182+
line=$(echo "$line" | sed -E "s/#([0-9]+)/[#\1](https:\/\/github.com\/${{ github.repository }}\/issues\/\1)/g")
183+
echo "$line" >> release_notes.md
184+
done < commits.txt
185+
else
186+
echo "Initial release of MBVPN $VERSION" >> release_notes.md
187+
fi
188+
189+
echo "" >> release_notes.md
190+
echo '```' >> release_notes.md
46191
47192
- name: Create GitHub Release
48193
env:
49194
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
50195
run: |
51196
gh release create ${{ github.event.inputs.version }} \
52197
--title "MBVPN ${{ github.event.inputs.version }}" \
53-
--notes "MBVPN Release ${{ github.event.inputs.version }}"
198+
--notes-file release_notes.md
54199
55200
build-binaries:
56201
needs: create-release
57-
runs-on: [self-hosted, ubuntu-22.04-2core]
202+
runs-on: ubuntu-latest
58203
environment: ${{ github.event.inputs.is_production == 'true' && 'prod' || 'stage' }}
59204
strategy:
60205
matrix:
@@ -76,7 +221,6 @@ jobs:
76221

77222
- name: Build for ${{ matrix.os }}-${{ matrix.arch }}
78223
env:
79-
MBVPN_HOLOCRON_URL: ${{ vars.MBVPN_HOLOCRON_URL }}
80224
VERSION_MAJOR: ${{ needs.create-release.outputs.MAJOR }}
81225
VERSION_MINOR: ${{ needs.create-release.outputs.MINOR }}
82226
VERSION_PATCH: ${{ needs.create-release.outputs.PATCH }}

.github/workflows/unit-tests.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,21 @@ permissions:
44

55
on:
66
push:
7-
branches: [ trunk ]
7+
branches: [trunk]
88
pull_request:
9-
branches: [ trunk ]
9+
branches: [trunk]
1010

1111
jobs:
1212
test:
1313
name: Run Unit Tests
14-
runs-on: [ubuntu-latest]
14+
runs-on: ubuntu-latest
1515
steps:
1616
- uses: actions/checkout@v4
1717

1818
- name: Set up Go
1919
uses: actions/setup-go@v5
2020
with:
21-
go-version: '1.24'
21+
go-version: "1.24"
2222
cache: true
2323

2424
- name: Install dependencies

Taskfile.yml

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,7 @@
11
version: "3"
22

3-
dotenv: [".env"]
4-
53
vars:
64
BINARY_NAME: mbvpn
7-
GO_PKG: github.com/malwarebytes/mbvpn-linux
8-
VERSION_MAJOR:
9-
sh: echo "${VERSION_MAJOR:-0}"
10-
VERSION_MINOR:
11-
sh: echo "${VERSION_MINOR:-0}"
12-
VERSION_PATCH:
13-
sh: echo "${VERSION_PATCH:-1}"
14-
VERSION_BUILD:
15-
sh: echo "${VERSION_BUILD:-0}"
16-
17-
# Common ldflags
18-
COMMON_LDFLAGS: >-
19-
-X '{{.GO_PKG}}/pkg/config.VersionMajor={{.VERSION_MAJOR}}'
20-
-X '{{.GO_PKG}}/pkg/config.VersionMinor={{.VERSION_MINOR}}'
21-
-X '{{.GO_PKG}}/pkg/config.VersionPatch={{.VERSION_PATCH}}'
22-
-X '{{.GO_PKG}}/pkg/config.VersionBuild={{.VERSION_BUILD}}'
23-
24-
# Environment ldflags
25-
ENV_LDFLAGS: >-
26-
-X '{{.GO_PKG}}/pkg/config.BuildEnv=production'
27-
-X '{{.GO_PKG}}/pkg/config.HolocronUrl={{.MBVPN_HOLOCRON_URL}}'
285

296
# Debug flags
307
DEBUG_GCFLAGS: -N -l
@@ -45,7 +22,6 @@ tasks:
4522
go build {{.GOFLAGS}}
4623
-o {{.BINARY_NAME}}
4724
-gcflags="{{.DEBUG_GCFLAGS}}"
48-
-ldflags "{{.COMMON_LDFLAGS}} {{.ENV_LDFLAGS}}"
4925
./cmd/mbvpn
5026
5127
build-release:
@@ -55,7 +31,6 @@ tasks:
5531
go build {{.GOFLAGS}}
5632
{{.RELEASE_BUILDFLAGS}}
5733
-o {{.BINARY_NAME}}
58-
-ldflags "{{.COMMON_LDFLAGS}} {{.ENV_LDFLAGS}}"
5934
./cmd/mbvpn
6035
6136
test:

cmd/version.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@ func NewVersionCommand() *cobra.Command {
1717
Short: "Display version information",
1818
Long: `Display the application version.`,
1919
Run: func(cmd *cobra.Command, args []string) {
20-
fmt.Printf("Version: %s\n", config.Version())
21-
fmt.Printf("Environment: %s\n", config.BuildEnv)
22-
fmt.Printf("Debug Mode: %t\n", config.Debug())
20+
fmt.Printf("v%s\n", config.Version())
2321
},
2422
}
2523
}

cmd/version_test.go

Lines changed: 14 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -47,46 +47,26 @@ func TestVersionCommandOutput(t *testing.T) {
4747

4848
var buf bytes.Buffer
4949
io.Copy(&buf, r)
50-
output := buf.String()
50+
output := strings.TrimSpace(buf.String())
5151

52-
// Verify output contains expected fields
53-
lines := strings.Split(strings.TrimSpace(output), "\n")
54-
if len(lines) != 3 {
55-
t.Errorf("Expected 4 lines of output, got %d", len(lines))
52+
// Verify output is single line
53+
if strings.Contains(output, "\n") {
54+
t.Errorf("Expected single line output, got multiple lines: %s", output)
5655
}
5756

58-
expectedPrefixes := []string{
59-
"Version: ",
60-
"Environment: ",
61-
"Debug Mode: ",
57+
// Verify output starts with "v"
58+
if !strings.HasPrefix(output, "v") {
59+
t.Errorf("Expected output to start with 'v', got: %s", output)
6260
}
6361

64-
for i, prefix := range expectedPrefixes {
65-
if i >= len(lines) || !strings.HasPrefix(lines[i], prefix) {
66-
t.Errorf("Line %d should start with '%s', got '%s'", i+1, prefix, lines[i])
67-
}
62+
// Verify version format matches "vX.Y.Z"
63+
expectedVersion := "v" + config.Version()
64+
if output != expectedVersion {
65+
t.Errorf("Expected version '%s', got '%s'", expectedVersion, output)
6866
}
6967

70-
// Verify version format (should be in format "0.0.1+0")
71-
versionLine := lines[0]
72-
versionValue := strings.TrimPrefix(versionLine, "Version: ")
73-
expectedVersion := config.Version()
74-
if versionValue != expectedVersion {
75-
t.Errorf("Expected version '%s', got '%s'", expectedVersion, versionValue)
76-
}
77-
78-
// Verify environment value
79-
envLine := lines[1]
80-
envValue := strings.TrimPrefix(envLine, "Environment: ")
81-
if envValue != config.BuildEnv {
82-
t.Errorf("Expected environment '%s', got '%s'", config.BuildEnv, envValue)
83-
}
84-
85-
// Verify debug mode value
86-
debugLine := lines[2]
87-
debugValue := strings.TrimPrefix(debugLine, "Debug Mode: ")
88-
expectedDebug := "true" // Since we're in testing mode, Debug() returns true
89-
if debugValue != expectedDebug {
90-
t.Errorf("Expected debug mode '%s', got '%s'", expectedDebug, debugValue)
68+
// Verify it contains dots (semantic version format)
69+
if !strings.Contains(output, ".") {
70+
t.Errorf("Expected version format 'vX.Y.Z', got: %s", output)
9171
}
9272
}

0 commit comments

Comments
 (0)