Skip to content

Commit 5f4f3b4

Browse files
committed
Add release workflow for v3
- Add GitHub Actions workflow for manual release creation - Update release bundle spec for v3 (ecosys-frogbot/v3) - Update buildAndUpload.sh to build 10 binaries in parallel - Workflow includes: version validation, tag creation, Frogbot scan, binary builds, release creation
1 parent 2b9b3f8 commit 5f4f3b4

File tree

4 files changed

+317
-107
lines changed

4 files changed

+317
-107
lines changed

.github/workflows/release.yml

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
name: Release Frogbot
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
version:
7+
description: 'Release version (e.g., v3.0.1 or 3.0.1)'
8+
required: true
9+
type: string
10+
11+
# Required permissions
12+
permissions:
13+
contents: write
14+
actions: read
15+
16+
jobs:
17+
release:
18+
name: Release Frogbot v3
19+
runs-on: self-hosted
20+
21+
steps:
22+
- name: Extract version from tag
23+
id: version
24+
run: |
25+
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
26+
# Manual trigger: use input version
27+
VERSION="${{ inputs.version }}"
28+
# Add 'v' prefix if not present
29+
if [[ ! "$VERSION" =~ ^v ]]; then
30+
TAG="v$VERSION"
31+
else
32+
TAG="$VERSION"
33+
VERSION="${VERSION#v}"
34+
fi
35+
elif [ "${{ github.event_name }}" == "push" ]; then
36+
# Push trigger: use test version with timestamp
37+
VERSION="3.0.0-test-$(date +%s)"
38+
TAG="v$VERSION"
39+
40+
# Validate it's a v3.x.x version (allows pre-release suffixes like -testing, -alpha, etc.)
41+
if [[ ! "$TAG" =~ ^v3\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]; then
42+
echo "❌ Error: Version must be v3.x.x format (e.g., v3.0.1, v3.0.0-testing)"
43+
echo "Got: $TAG"
44+
exit 1
45+
fi
46+
else
47+
# Release trigger: use release tag
48+
TAG="${{ github.event.release.tag_name }}"
49+
VERSION="${TAG#v}"
50+
fi
51+
echo "version=$VERSION" >> $GITHUB_OUTPUT
52+
echo "tag=$TAG" >> $GITHUB_OUTPUT
53+
echo "✅ Release version: $VERSION"
54+
echo "✅ Release tag: $TAG"
55+
56+
- name: Check if tag already exists
57+
if: github.event_name == 'workflow_dispatch'
58+
uses: actions/github-script@v7
59+
with:
60+
script: |
61+
const tag = '${{ steps.version.outputs.tag }}';
62+
63+
try {
64+
// Check if tag exists
65+
await github.rest.git.getRef({
66+
owner: context.repo.owner,
67+
repo: context.repo.repo,
68+
ref: `tags/${tag}`
69+
});
70+
71+
// Tag exists - fail the workflow
72+
core.setFailed(`❌ Tag ${tag} already exists! Please use a different version.`);
73+
} catch (error) {
74+
if (error.status === 404) {
75+
// Tag doesn't exist - good to proceed
76+
console.log(`✅ Tag ${tag} does not exist, proceeding with release`);
77+
} else {
78+
// Some other error
79+
throw error;
80+
}
81+
}
82+
83+
- name: Checkout code
84+
uses: actions/checkout@v4
85+
with:
86+
ref: ${{ github.event_name == 'workflow_dispatch' && github.ref || github.event.release.tag_name }}
87+
fetch-depth: 0
88+
89+
- name: Set up Go
90+
uses: actions/setup-go@v5
91+
with:
92+
go-version-file: 'go.mod'
93+
cache: true
94+
95+
- name: Download JFrog CLI
96+
run: |
97+
curl -fL https://install-cli.jfrog.io | sh
98+
# The install script already moves jf to /usr/local/bin/
99+
100+
- name: Configure JFrog CLI
101+
env:
102+
JF_URL: ${{ secrets.JF_URL }}
103+
JF_ACCESS_TOKEN: ${{ secrets.JF_ACCESS_TOKEN }}
104+
run: |
105+
jf c rm --quiet || true
106+
jf c add internal --url="$JF_URL" --access-token="$JF_ACCESS_TOKEN"
107+
jf goc --repo-resolve ecosys-go-virtual
108+
109+
- name: Generate mocks
110+
run: go generate ./...
111+
112+
- name: Set up Node.js for Action
113+
uses: actions/setup-node@v4
114+
with:
115+
node-version: '16'
116+
cache: 'npm'
117+
cache-dependency-path: action/package-lock.json
118+
119+
- name: Run Frogbot scan before release
120+
uses: jfrog/frogbot@v2
121+
env:
122+
JF_URL: ${{ secrets.JF_URL }}
123+
JF_ACCESS_TOKEN: ${{ secrets.JF_ACCESS_TOKEN }}
124+
JF_GIT_TOKEN: ${{ secrets.GITHUB_TOKEN }}
125+
JF_GIT_BASE_BRANCH: ${{ github.ref_name }}
126+
JF_FAIL: "true"
127+
JF_SKIP_AUTOFIX: "true"
128+
129+
- name: Create release tag
130+
run: |
131+
git config user.name "github-actions[bot]"
132+
git config user.email "github-actions[bot]@users.noreply.github.com"
133+
echo "Creating tag ${{ steps.version.outputs.tag }}..."
134+
git tag -f ${{ steps.version.outputs.tag }}
135+
git push origin ${{ steps.version.outputs.tag }} --force
136+
echo "Tag ${{ steps.version.outputs.tag }} created"
137+
138+
- name: Update GitHub Action major version tag (v3)
139+
run: |
140+
# Update v3 tag to point to the latest v3.x.x release
141+
git tag -f v3
142+
git push origin v3 --force
143+
echo "Updated v3 tag to ${{ steps.version.outputs.tag }}"
144+
145+
- name: Build and upload binaries (parallel)
146+
env:
147+
VERSION: ${{ steps.version.outputs.tag }}
148+
JFROG_CLI_BUILD_NAME: ecosystem-frogbot-release
149+
JFROG_CLI_BUILD_NUMBER: ${{ github.run_number }}
150+
JFROG_CLI_BUILD_PROJECT: ecosys
151+
run: |
152+
env -i PATH=$PATH HOME=$HOME \
153+
JFROG_CLI_BUILD_NAME=$JFROG_CLI_BUILD_NAME \
154+
JFROG_CLI_BUILD_NUMBER=$JFROG_CLI_BUILD_NUMBER \
155+
JFROG_CLI_BUILD_PROJECT=$JFROG_CLI_BUILD_PROJECT \
156+
CI=true \
157+
release/buildAndUpload.sh "${{ steps.version.outputs.version }}"
158+
159+
- name: Publish build info
160+
env:
161+
JFROG_CLI_BUILD_NAME: ecosystem-frogbot-release
162+
JFROG_CLI_BUILD_NUMBER: ${{ github.run_number }}
163+
JFROG_CLI_BUILD_PROJECT: ecosys
164+
run: |
165+
jf rt bag
166+
jf rt bce
167+
jf rt bp
168+
169+
- name: Create and distribute release bundle
170+
env:
171+
VERSION: ${{ steps.version.outputs.version }}
172+
run: |
173+
# Use same JFrog CLI config (internal) for distribution
174+
jf ds rbc ecosystem-frogbot $VERSION \
175+
--spec="release/specs/frogbot-rbc-spec.json" \
176+
--spec-vars="VERSION=$VERSION" \
177+
--sign
178+
jf ds rbd ecosystem-frogbot $VERSION \
179+
--site="releases.jfrog.io" \
180+
--sync
181+
182+
- name: Create GitHub Release
183+
if: github.event_name == 'workflow_dispatch'
184+
uses: actions/github-script@v7
185+
with:
186+
script: |
187+
const tag = '${{ steps.version.outputs.tag }}';
188+
189+
// Check if this is a pre-release version (contains hyphen like v3.0.0-testing)
190+
const isPrerelease = tag.includes('-');
191+
192+
console.log(`Creating release for tag ${tag}`);
193+
if (isPrerelease) {
194+
console.log(`⚠️ This will be marked as a pre-release`);
195+
}
196+
197+
// The tag was already created and pushed in the previous step
198+
// Now create the release with auto-generated notes
199+
const release = await github.rest.repos.createRelease({
200+
owner: context.repo.owner,
201+
repo: context.repo.repo,
202+
tag_name: tag,
203+
name: `Release ${tag}`,
204+
generate_release_notes: true,
205+
draft: false,
206+
prerelease: isPrerelease,
207+
make_latest: false
208+
});
209+
210+
console.log(`✅ Created release ${release.data.id} for ${tag}`);
211+
console.log(`📦 Release URL: ${release.data.html_url}`);
212+
console.log(`ℹ️ This release is NOT marked as "Latest"`);
213+
214+
- name: Cleanup JFrog config
215+
if: always()
216+
run: jf c rm --quiet || true
217+
218+
# On failure: delete release and tag
219+
- name: Delete release on failure
220+
if: failure()
221+
uses: actions/github-script@v7
222+
with:
223+
script: |
224+
const tag = '${{ steps.version.outputs.tag }}';
225+
226+
console.log(`Workflow failed, cleaning up tag ${tag}`);
227+
228+
try {
229+
// Try to find and delete the release
230+
const releases = await github.rest.repos.listReleases({
231+
owner: context.repo.owner,
232+
repo: context.repo.repo
233+
});
234+
235+
const release = releases.data.find(r => r.tag_name === tag);
236+
if (release) {
237+
console.log(`Deleting release ${release.id}`);
238+
await github.rest.repos.deleteRelease({
239+
owner: context.repo.owner,
240+
repo: context.repo.repo,
241+
release_id: release.id
242+
});
243+
console.log('Release deleted');
244+
} else {
245+
console.log('No release found to delete');
246+
}
247+
248+
// Delete the tag
249+
try {
250+
await github.rest.git.deleteRef({
251+
owner: context.repo.owner,
252+
repo: context.repo.repo,
253+
ref: `tags/${tag}`
254+
});
255+
console.log('Tag deleted');
256+
} catch (error) {
257+
console.log(`Tag deletion failed or tag doesn't exist: ${error.message}`);
258+
}
259+
} catch (error) {
260+
console.error(`Cleanup failed: ${error.message}`);
261+
// Don't fail the workflow if cleanup fails
262+
}
263+

release/buildAndUpload.sh

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ build () {
1414

1515
# Run verification after building plugin for the correct platform of this image.
1616
if [[ "$pkg" = "frogbot-linux-386" ]]; then
17-
verifyVersionMatching
17+
verifyVersionMatching "$exeName"
1818
fi
1919
}
2020

@@ -24,19 +24,26 @@ buildAndUpload () {
2424
goos="$2"
2525
goarch="$3"
2626
fileExtension="$4"
27-
exeName="frogbot$fileExtension"
27+
# Use unique filename during build to avoid parallel conflicts
28+
uniqueExeName="${pkg}${fileExtension}"
29+
finalExeName="frogbot$fileExtension"
2830

29-
build "$pkg" "$goos" "$goarch" "$exeName"
31+
build "$pkg" "$goos" "$goarch" "$uniqueExeName"
3032

31-
destPath="$pkgPath/$version/$pkg/$exeName"
32-
echo "Uploading $exeName to $destPath ..."
33-
jf rt u "./$exeName" "$destPath"
33+
destPath="$pkgPath/$version/$pkg/$finalExeName"
34+
echo "Uploading $uniqueExeName to $destPath ..."
35+
jf rt u "./$uniqueExeName" "$destPath"
36+
37+
# Clean up the unique build file after upload
38+
rm -f "./$uniqueExeName"
3439
}
3540

3641
# Verify version provided in pipelines UI matches version in frogbot source code.
42+
# Takes the executable name as parameter
3743
verifyVersionMatching () {
44+
local exePath="$1"
3845
echo "Verifying provided version matches built version..."
39-
res=$(eval "./frogbot -v")
46+
res=$(eval "./$exePath -v")
4047
exitCode=$?
4148
if [[ $exitCode -ne 0 ]]; then
4249
echo "Error: Failed verifying version matches"
@@ -55,19 +62,47 @@ verifyVersionMatching () {
5562
}
5663

5764
version="$1"
58-
pkgPath="ecosys-frogbot/v2"
65+
# Extract major version (e.g., "3.1.1" -> "3")
66+
majorVersion="${version%%.*}"
67+
# Allow overriding repository name via environment variable
68+
repoName="${FROGBOT_REPO_NAME:-ecosys-frogbot}"
69+
pkgPath="${repoName}/v${majorVersion}"
5970

6071
# Build and upload for every architecture.
6172
# Keep 'linux-386' first to prevent unnecessary uploads in case the built version doesn't match the provided one.
73+
echo "Building linux-386 first for version verification..."
6274
buildAndUpload 'frogbot-linux-386' 'linux' '386' ''
63-
buildAndUpload 'frogbot-linux-amd64' 'linux' 'amd64' ''
64-
buildAndUpload 'frogbot-linux-s390x' 'linux' 's390x' ''
65-
buildAndUpload 'frogbot-linux-arm64' 'linux' 'arm64' ''
66-
buildAndUpload 'frogbot-linux-arm' 'linux' 'arm' ''
67-
buildAndUpload 'frogbot-linux-ppc64' 'linux' 'ppc64' ''
68-
buildAndUpload 'frogbot-linux-ppc64le' 'linux' 'ppc64le' ''
69-
buildAndUpload 'frogbot-mac-386' 'darwin' 'amd64' ''
70-
buildAndUpload 'frogbot-mac-arm64' 'darwin' 'arm64' ''
71-
buildAndUpload 'frogbot-windows-amd64' 'windows' 'amd64' '.exe'
75+
76+
# Build the rest in parallel for speed
77+
echo ""
78+
echo "Building remaining 9 platforms in parallel..."
79+
pids=()
80+
81+
buildAndUpload 'frogbot-linux-amd64' 'linux' 'amd64' '' & pids+=($!)
82+
buildAndUpload 'frogbot-linux-s390x' 'linux' 's390x' '' & pids+=($!)
83+
buildAndUpload 'frogbot-linux-arm64' 'linux' 'arm64' '' & pids+=($!)
84+
buildAndUpload 'frogbot-linux-arm' 'linux' 'arm' '' & pids+=($!)
85+
buildAndUpload 'frogbot-linux-ppc64' 'linux' 'ppc64' '' & pids+=($!)
86+
buildAndUpload 'frogbot-linux-ppc64le' 'linux' 'ppc64le' '' & pids+=($!)
87+
buildAndUpload 'frogbot-mac-386' 'darwin' 'amd64' '' & pids+=($!)
88+
buildAndUpload 'frogbot-mac-arm64' 'darwin' 'arm64' '' & pids+=($!)
89+
buildAndUpload 'frogbot-windows-amd64' 'windows' 'amd64' '.exe' & pids+=($!)
90+
91+
# Wait for all background jobs and check for failures
92+
echo "Waiting for all parallel builds to complete..."
93+
failed=0
94+
for pid in "${pids[@]}"; do
95+
wait $pid || failed=1
96+
done
97+
98+
if [ $failed -eq 1 ]; then
99+
echo "❌ One or more builds failed!"
100+
exit 1
101+
fi
102+
103+
echo ""
104+
echo "✅ All builds completed successfully!"
105+
echo ""
72106

73107
jf rt u "./buildscripts/getFrogbot.sh" "$pkgPath/$version/" --flat
108+

0 commit comments

Comments
 (0)