Skip to content

Commit 02e1e60

Browse files
authored
Merge pull request #23 from chef/sean-sype-simmons/AddVersioningforWorkflows
updating initial workflows to create tags
2 parents 76055b3 + 9b9d221 commit 02e1e60

File tree

6 files changed

+1474
-12
lines changed

6 files changed

+1474
-12
lines changed
Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
# Workflow to create a git tag when code is merged to main branch
2+
# This tag can be used to version projects that reference this repository
3+
#
4+
# Usage: Projects can reference a specific version of common-github-actions using the tag:
5+
# uses: chef/common-github-actions/.github/workflows/ci-main-pull-request.yml@v1.0.7
6+
#
7+
# Tag format: v{MAJOR}.{MINOR}.{PATCH}
8+
# - MAJOR: Breaking changes
9+
# - MINOR: New features, backward compatible
10+
# - PATCH: Bug fixes, backward compatible
11+
#
12+
# This workflow can be:
13+
# 1. Used directly in this repository (triggers on push/workflow_dispatch)
14+
# 2. Called by other repositories via workflow_call
15+
16+
name: Create Release Tag on Merge
17+
18+
on:
19+
push:
20+
branches:
21+
- main
22+
workflow_dispatch:
23+
inputs:
24+
version_bump:
25+
description: 'Version bump type'
26+
required: true
27+
default: 'patch'
28+
type: choice
29+
options:
30+
- major
31+
- minor
32+
- patch
33+
custom_version:
34+
description: 'Custom version (overrides version_bump, format: X.Y.Z without v prefix)'
35+
required: false
36+
type: string
37+
workflow_call:
38+
inputs:
39+
version_bump:
40+
description: 'Version bump type (major, minor, patch)'
41+
required: false
42+
type: string
43+
default: 'patch'
44+
custom_version:
45+
description: 'Custom version (overrides version_bump, format: X.Y.Z without v prefix)'
46+
required: false
47+
type: string
48+
default: ''
49+
50+
permissions:
51+
contents: write
52+
53+
env:
54+
WORKFLOW_VERSION: '1.0.0'
55+
56+
jobs:
57+
create-tag:
58+
name: 'Create Release Tag'
59+
runs-on: ubuntu-latest
60+
outputs:
61+
new_tag: ${{ steps.create_tag.outputs.new_tag }}
62+
previous_tag: ${{ steps.get_latest_tag.outputs.latest_tag }}
63+
64+
steps:
65+
- name: Checkout repository
66+
uses: actions/checkout@v4
67+
with:
68+
fetch-depth: 0
69+
fetch-tags: true
70+
71+
- name: Get latest tag
72+
id: get_latest_tag
73+
run: |
74+
# Get the latest tag, default to v0.0.0 if no tags exist
75+
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
76+
echo "latest_tag=${LATEST_TAG}" >> $GITHUB_OUTPUT
77+
echo "Latest tag: ${LATEST_TAG}"
78+
79+
- name: Validate and parse version
80+
id: calc_version
81+
run: |
82+
LATEST_TAG="${{ steps.get_latest_tag.outputs.latest_tag }}"
83+
84+
# Function to validate semver format (vX.Y.Z or X.Y.Z where X, Y, Z are integers)
85+
validate_semver() {
86+
local version="$1"
87+
local stripped="${version#v}" # Remove 'v' prefix if present
88+
89+
# Check if it matches X.Y.Z where X, Y, Z are non-negative integers
90+
if [[ "$stripped" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
91+
echo "valid"
92+
else
93+
echo "invalid"
94+
fi
95+
}
96+
97+
# Function to extract semver components
98+
extract_semver() {
99+
local version="$1"
100+
local stripped="${version#v}" # Remove 'v' prefix if present
101+
102+
# Extract just the X.Y.Z part, ignoring any suffix like -rc1, -beta, etc.
103+
if [[ "$stripped" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+) ]]; then
104+
echo "${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}"
105+
else
106+
echo ""
107+
fi
108+
}
109+
110+
# Handle custom version input
111+
if [ -n "${{ inputs.custom_version }}" ]; then
112+
CUSTOM_VER="${{ inputs.custom_version }}"
113+
CUSTOM_VER="${CUSTOM_VER#v}" # Strip 'v' prefix if user included it
114+
115+
if [[ "$(validate_semver "$CUSTOM_VER")" != "valid" ]]; then
116+
echo "❌ Error: Custom version '$CUSTOM_VER' is not a valid semantic version."
117+
echo " Expected format: X.Y.Z (e.g., 1.2.3)"
118+
echo " Each component must be a non-negative integer."
119+
exit 1
120+
fi
121+
122+
echo "Using custom version: ${CUSTOM_VER}"
123+
echo "new_version=${CUSTOM_VER}" >> $GITHUB_OUTPUT
124+
exit 0
125+
fi
126+
127+
# Validate latest tag format
128+
EXTRACTED_VERSION=$(extract_semver "$LATEST_TAG")
129+
130+
if [ -z "$EXTRACTED_VERSION" ]; then
131+
echo "⚠️ Warning: Latest tag '$LATEST_TAG' is not a valid semantic version."
132+
echo " Expected format: vX.Y.Z (e.g., v1.2.3)"
133+
echo " Starting from v0.0.0 instead."
134+
EXTRACTED_VERSION="0.0.0"
135+
elif [ "$EXTRACTED_VERSION" != "${LATEST_TAG#v}" ]; then
136+
echo "⚠️ Warning: Latest tag '$LATEST_TAG' contains a suffix."
137+
echo " Using base version: $EXTRACTED_VERSION"
138+
fi
139+
140+
# Split version into parts
141+
MAJOR=$(echo "$EXTRACTED_VERSION" | cut -d. -f1)
142+
MINOR=$(echo "$EXTRACTED_VERSION" | cut -d. -f2)
143+
PATCH=$(echo "$EXTRACTED_VERSION" | cut -d. -f3)
144+
145+
# Verify components are numeric (defensive check)
146+
if ! [[ "$MAJOR" =~ ^[0-9]+$ ]] || ! [[ "$MINOR" =~ ^[0-9]+$ ]] || ! [[ "$PATCH" =~ ^[0-9]+$ ]]; then
147+
echo "❌ Error: Version components must be numeric."
148+
echo " Got: MAJOR=$MAJOR, MINOR=$MINOR, PATCH=$PATCH"
149+
exit 1
150+
fi
151+
152+
# Default to patch bump for push events, use input for workflow_dispatch
153+
BUMP_TYPE="${{ inputs.version_bump }}"
154+
if [ -z "$BUMP_TYPE" ]; then
155+
BUMP_TYPE="patch"
156+
fi
157+
158+
# Calculate new version based on bump type
159+
case $BUMP_TYPE in
160+
major)
161+
MAJOR=$((MAJOR + 1))
162+
MINOR=0
163+
PATCH=0
164+
;;
165+
minor)
166+
MINOR=$((MINOR + 1))
167+
PATCH=0
168+
;;
169+
patch)
170+
PATCH=$((PATCH + 1))
171+
;;
172+
*)
173+
echo "❌ Error: Invalid bump type '$BUMP_TYPE'. Must be one of: major, minor, patch"
174+
exit 1
175+
;;
176+
esac
177+
178+
NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}"
179+
echo "new_version=${NEW_VERSION}" >> $GITHUB_OUTPUT
180+
echo "Bump type: ${BUMP_TYPE}"
181+
echo "New version: ${NEW_VERSION}"
182+
183+
- name: Check if tag already exists
184+
id: check_tag
185+
run: |
186+
NEW_TAG="v${{ steps.calc_version.outputs.new_version }}"
187+
if git rev-parse "$NEW_TAG" >/dev/null 2>&1; then
188+
echo "Tag ${NEW_TAG} already exists!"
189+
echo "exists=true" >> $GITHUB_OUTPUT
190+
else
191+
echo "Tag ${NEW_TAG} does not exist, proceeding with creation"
192+
echo "exists=false" >> $GITHUB_OUTPUT
193+
fi
194+
195+
- name: Create and push tag
196+
id: create_tag
197+
if: steps.check_tag.outputs.exists == 'false'
198+
run: |
199+
NEW_TAG="v${{ steps.calc_version.outputs.new_version }}"
200+
201+
# Configure git
202+
git config user.name "github-actions[bot]"
203+
git config user.email "github-actions[bot]@users.noreply.github.com"
204+
205+
# Create annotated tag with message
206+
git tag -a "${NEW_TAG}" -m "Release ${NEW_TAG}
207+
208+
Automated release tag created on merge to main branch.
209+
210+
Previous version: ${{ steps.get_latest_tag.outputs.latest_tag }}
211+
Commit: ${{ github.sha }}
212+
Triggered by: ${{ github.actor }}"
213+
214+
# Push the tag
215+
git push origin "${NEW_TAG}"
216+
217+
echo "new_tag=${NEW_TAG}" >> $GITHUB_OUTPUT
218+
echo "✅ Created and pushed tag: ${NEW_TAG}"
219+
220+
- name: Skip tag creation (already exists)
221+
if: steps.check_tag.outputs.exists == 'true'
222+
run: |
223+
echo "⚠️ Skipping tag creation - tag v${{ steps.calc_version.outputs.new_version }} already exists"
224+
225+
- name: Output summary
226+
run: |
227+
echo "## 🏷️ Release Tag Summary" >> $GITHUB_STEP_SUMMARY
228+
echo "" >> $GITHUB_STEP_SUMMARY
229+
echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY
230+
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
231+
echo "| Previous Tag | ${{ steps.get_latest_tag.outputs.latest_tag }} |" >> $GITHUB_STEP_SUMMARY
232+
echo "| New Tag | v${{ steps.calc_version.outputs.new_version }} |" >> $GITHUB_STEP_SUMMARY
233+
echo "| Commit SHA | ${{ github.sha }} |" >> $GITHUB_STEP_SUMMARY
234+
echo "| Actor | ${{ github.actor }} |" >> $GITHUB_STEP_SUMMARY
235+
echo "| Workflow Version | ${{ env.WORKFLOW_VERSION }} |" >> $GITHUB_STEP_SUMMARY
236+
echo "" >> $GITHUB_STEP_SUMMARY
237+
echo "### Usage" >> $GITHUB_STEP_SUMMARY
238+
echo "" >> $GITHUB_STEP_SUMMARY
239+
echo "Reference this version in your workflow:" >> $GITHUB_STEP_SUMMARY
240+
echo "" >> $GITHUB_STEP_SUMMARY
241+
echo "\`\`\`yaml" >> $GITHUB_STEP_SUMMARY
242+
echo "uses: chef/common-github-actions/.github/workflows/ci-main-pull-request.yml@v${{ steps.calc_version.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY
243+
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
244+
245+
create-release:
246+
name: 'Create GitHub Release'
247+
runs-on: ubuntu-latest
248+
needs: create-tag
249+
if: needs.create-tag.outputs.new_tag != ''
250+
251+
steps:
252+
- name: Checkout repository
253+
uses: actions/checkout@v4
254+
with:
255+
fetch-depth: 0
256+
ref: ${{ needs.create-tag.outputs.new_tag }}
257+
258+
- name: Generate release notes
259+
id: release_notes
260+
run: |
261+
PREVIOUS_TAG="${{ needs.create-tag.outputs.previous_tag }}"
262+
NEW_TAG="${{ needs.create-tag.outputs.new_tag }}"
263+
264+
# Generate changelog between tags
265+
if [ "$PREVIOUS_TAG" != "v0.0.0" ]; then
266+
CHANGELOG=$(git log --pretty=format:"- %s (%h)" ${PREVIOUS_TAG}..HEAD 2>/dev/null || echo "- Initial release")
267+
else
268+
CHANGELOG="- Initial release"
269+
fi
270+
271+
# Write to file for multi-line handling
272+
cat > release_notes.md << EOF
273+
## What's Changed
274+
275+
${CHANGELOG}
276+
277+
## Usage
278+
279+
Reference this version in your workflow:
280+
281+
\`\`\`yaml
282+
jobs:
283+
call-ci-main-pr-check-pipeline:
284+
uses: chef/common-github-actions/.github/workflows/ci-main-pull-request.yml@${NEW_TAG}
285+
secrets: inherit
286+
permissions:
287+
id-token: write
288+
contents: read
289+
\`\`\`
290+
291+
## Full Changelog
292+
293+
https://github.com/${{ github.repository }}/compare/${PREVIOUS_TAG}...${NEW_TAG}
294+
EOF
295+
296+
- name: Create GitHub Release
297+
uses: softprops/action-gh-release@v2
298+
with:
299+
tag_name: ${{ needs.create-tag.outputs.new_tag }}
300+
name: "Release ${{ needs.create-tag.outputs.new_tag }}"
301+
body_path: release_notes.md
302+
draft: false
303+
prerelease: false
304+
generate_release_notes: true
305+
env:
306+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/stubs/ci-main-pull-request-stub.yml

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,12 @@ on:
1515

1616
permissions:
1717
contents: read
18-
19-
env:
20-
STUB_VERSION: "1.0.7"
2118

2219
jobs:
23-
echo_version:
24-
name: 'Echo stub version'
25-
runs-on: ubuntu-latest
26-
steps:
27-
- name: echo version of stub and inputs
28-
run: |
29-
echo "CI main pull request stub version $STUB_VERSION"
30-
3120
call-ci-main-pr-check-pipeline:
32-
uses: chef/common-github-actions/.github/workflows/ci-main-pull-request.yml@main
21+
# To pin to a specific version, change @main to a tag like @v1.0.7
22+
# Available tags: https://github.com/chef/common-github-actions/tags
23+
uses: chef/common-github-actions/.github/workflows/ci-main-pull-request.yml@main # or use @v1.0.7
3324
secrets: inherit
3425
permissions:
3526
id-token: write
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Stub to call the common GitHub Action for creating release tags
2+
# Copy this file to your repository's .github/workflows/ directory
3+
#
4+
# This workflow will create a git tag when code is merged to main branch
5+
# Projects can then reference a specific version of common-github-actions
6+
7+
name: Create Release Tag
8+
9+
on:
10+
push:
11+
branches:
12+
- main
13+
workflow_dispatch:
14+
inputs:
15+
version_bump:
16+
description: 'Version bump type'
17+
required: true
18+
default: 'patch'
19+
type: choice
20+
options:
21+
- major
22+
- minor
23+
- patch
24+
custom_version:
25+
description: 'Custom version (overrides version_bump, format: X.Y.Z without v prefix)'
26+
required: false
27+
type: string
28+
29+
permissions:
30+
contents: write
31+
32+
jobs:
33+
call-create-release-tag:
34+
# To pin to a specific version, change @main to a tag like @v1.0.7
35+
# Available tags: https://github.com/chef/common-github-actions/tags
36+
uses: chef/common-github-actions/.github/workflows/create-release-tag.yml@main
37+
secrets: inherit
38+
permissions:
39+
contents: write
40+
with:
41+
version_bump: ${{ inputs.version_bump || 'patch' }}
42+
custom_version: ${{ inputs.custom_version || '' }}

0 commit comments

Comments
 (0)