-
Notifications
You must be signed in to change notification settings - Fork 21
update release process #101
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,17 +1,17 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| name: Auto Release on Release Branch | ||||||||||||||||||||||||||||||||||||||||||||||||||
| name: Auto Release on Main Branch | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| on: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| pull_request: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| types: [ closed ] | ||||||||||||||||||||||||||||||||||||||||||||||||||
| branches: [ release ] | ||||||||||||||||||||||||||||||||||||||||||||||||||
| branches: [ main ] | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| permissions: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| contents: write | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| jobs: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| auto-release: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| # Only run if PR was merged to release branch (not just closed) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if: github.event.pull_request.merged == true | ||||||||||||||||||||||||||||||||||||||||||||||||||
| # Only run if PR was merged from release branch to main and contains release label | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if: github.event.pull_request.merged == true && github.event.pull_request.head.ref == 'release' && contains(github.event.pull_request.labels.*.name, 'release') | ||||||||||||||||||||||||||||||||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -20,96 +20,179 @@ jobs: | |||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| fetch-depth: 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Extract tags from PR labels | ||||||||||||||||||||||||||||||||||||||||||||||||||
| id: get_tags_labels | ||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Extract and validate required labels | ||||||||||||||||||||||||||||||||||||||||||||||||||
| id: get_labels | ||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||
| # Get PR labels and extract version | ||||||||||||||||||||||||||||||||||||||||||||||||||
| # Get PR labels | ||||||||||||||||||||||||||||||||||||||||||||||||||
| LABELS='${{ toJson(github.event.pull_request.labels.*.name) }}' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "PR Labels: $LABELS" | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| # Look for version label (e.g., "v1.0.0", "version:1.0.0", etc.) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| VERSION=$(echo $LABELS | jq -r '.[] | select(test("^(v|version:)?[0-9]+\\.[0-9]+\\.[0-9]+")) | gsub("^(v|version:)"; "")') | ||||||||||||||||||||||||||||||||||||||||||||||||||
| # Look for version label in x.x.x format (e.g., "1.0.0", "2.1.3") - MANDATORY | ||||||||||||||||||||||||||||||||||||||||||||||||||
| VERSION=$(echo $LABELS | jq -r '.[] | select(test("^[0-9]+\\.[0-9]+\\.[0-9]+$"))') | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| # Look for zeam network tags (devnet0, devnet1, testnet, mainnet) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ZEAM_TAG=$(echo $LABELS | jq -r '.[] | select(test("^(devnet[0-9]+|testnet[0-9]*|mainnet)$"))') | ||||||||||||||||||||||||||||||||||||||||||||||||||
| # Look for devnet labels (devnet0, devnet1, devnet2, etc.) - MANDATORY | ||||||||||||||||||||||||||||||||||||||||||||||||||
| DEVNET_LABEL=$(echo $LABELS | jq -r '.[] | select(test("^devnet[0-9]+$"))') | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| # Check for mandatory labels - both version and devnet are required | ||||||||||||||||||||||||||||||||||||||||||||||||||
| MISSING_LABELS="" | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ -z "$VERSION" ] || [ "$VERSION" = "null" ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "ℹ️ No version label found" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "version=$VERSION" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "git_tag=v$VERSION" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "✅ Version found: $VERSION" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| MISSING_LABELS="version label (e.g., 1.0.0)" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ -n "$ZEAM_TAG" ] && [ "$ZEAM_TAG" != "null" ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "zeam_tag=$ZEAM_TAG" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "has_network_tag=true" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "✅ Found network tag: $ZEAM_TAG" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "has_network_tag=false" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "ℹ️ No network tag found (optional)" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ -z "$DEVNET_LABEL" ] || [ "$DEVNET_LABEL" = "null" ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ -n "$MISSING_LABELS" ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||
| MISSING_LABELS="$MISSING_LABELS and devnet label (devnet0, devnet1, devnet2, etc.)" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||
| MISSING_LABELS="devnet label (devnet0, devnet1, devnet2, etc.)" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| # Require at least one label (version or network) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if { [ -z "$VERSION" ] || [ "$VERSION" = "null" ]; } && { [ -z "$ZEAM_TAG" ] || [ "$ZEAM_TAG" = "null" ]; }; then | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "❌ No usable label found! Please add a version (e.g. v1.0.0) or network tag (e.g. devnet0, testnet, mainnet)" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| # Exit if any required labels are missing | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ -n "$MISSING_LABELS" ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "❌ Missing required labels: $MISSING_LABELS" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "Please add all required labels to proceed with the release." | ||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Create and push git tags | ||||||||||||||||||||||||||||||||||||||||||||||||||
| id: create_tags | ||||||||||||||||||||||||||||||||||||||||||||||||||
| # Check if version tag already exists (add 'v' prefix for git tag) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| VERSION_TAG="v$VERSION" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if git rev-parse "$VERSION_TAG" >/dev/null 2>&1; then | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "❌ Version tag $VERSION_TAG already exists. Please use a new version." | ||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| # Create proper naming to avoid branch/tag conflicts | ||||||||||||||||||||||||||||||||||||||||||||||||||
| DEVNET_TAG="$(echo $DEVNET_LABEL | sed 's/^d/D/')" # devnet1 -> Devnet1 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| DEVNET_BRANCH="$DEVNET_LABEL" # devnet1 | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| # Set outputs only after validation passes | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "version=$VERSION" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "git_tag=$VERSION_TAG" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "devnet_label=$DEVNET_LABEL" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "devnet_tag=$DEVNET_TAG" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "devnet_branch=$DEVNET_BRANCH" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "✅ Found version: $VERSION and devnet label: $DEVNET_LABEL" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "✅ Will create branch: $DEVNET_BRANCH and tag: $DEVNET_TAG" | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "✅ All required labels validated" | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Delete existing devnet tag and release if present | ||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||
| DEVNET_TAG="${{ steps.get_labels.outputs.devnet_tag }}" | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| # Check if tag exists and delete it | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if git rev-parse "$DEVNET_TAG" >/dev/null 2>&1; then | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "🗑️ Deleting existing tag $DEVNET_TAG" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| git tag -d "$DEVNET_TAG" 2>/dev/null || true | ||||||||||||||||||||||||||||||||||||||||||||||||||
| git push origin --delete "$DEVNET_TAG" 2>/dev/null || true | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "✅ Deleted existing tag $DEVNET_TAG" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "ℹ️ Tag $DEVNET_TAG does not exist" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| # Delete GitHub release if it exists | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "🗑️ Attempting to delete existing GitHub release $DEVNET_TAG" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| gh release delete "$DEVNET_TAG" --yes 2>/dev/null || echo "ℹ️ Release $DEVNET_TAG does not exist or already deleted" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Create/Update devnet branch | ||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||
| git config user.name "github-actions[bot]" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| CREATE_VERSION_TAG=false | ||||||||||||||||||||||||||||||||||||||||||||||||||
| CREATE_NETWORK_TAG=false | ||||||||||||||||||||||||||||||||||||||||||||||||||
| DEVNET_BRANCH="${{ steps.get_labels.outputs.devnet_branch }}" | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| # Check if version tag should be created | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ -n "${{ steps.get_tags_labels.outputs.version }}" ] && [ "${{ steps.get_tags_labels.outputs.version }}" != "null" ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if git rev-parse "${{ steps.get_tags_labels.outputs.git_tag }}" >/dev/null 2>&1; then | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "❌ Version tag ${{ steps.get_tags_labels.outputs.git_tag }} already exists. Please create a new tag." | ||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||
| CREATE_VERSION_TAG=true | ||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||
| # Check if devnet branch already exists remotely | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if git ls-remote --heads origin "$DEVNET_BRANCH" | grep -q "$DEVNET_BRANCH"; then | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "ℹ️ Branch $DEVNET_BRANCH already exists remotely" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| git checkout "$DEVNET_BRANCH" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| git pull origin "$DEVNET_BRANCH" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "✅ Creating new branch $DEVNET_BRANCH from main" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| git checkout -b "$DEVNET_BRANCH" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+110
to
116
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| git checkout "$DEVNET_BRANCH" | |
| git pull origin "$DEVNET_BRANCH" | |
| else | |
| echo "✅ Creating new branch $DEVNET_BRANCH from main" | |
| git checkout -b "$DEVNET_BRANCH" | |
| fi | |
| # Ensure local devnet branch matches the remote state | |
| git fetch origin "$DEVNET_BRANCH" | |
| git checkout -B "$DEVNET_BRANCH" "origin/$DEVNET_BRANCH" | |
| else | |
| echo "✅ Creating new branch $DEVNET_BRANCH from main" | |
| # Base new devnet branch on the latest origin/main | |
| git fetch origin main | |
| git checkout -B "$DEVNET_BRANCH" origin/main | |
| fi | |
| # Ensure local main is up to date with origin/main before merging | |
| git fetch origin main:main |
Copilot
AI
Jan 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The merge operation may fail if there are conflicts between the main branch and the existing devnet branch. This scenario is not handled, and the workflow will fail without a clear resolution path. Consider adding conflict detection and appropriate error messaging to guide users on how to resolve conflicts manually.
Copilot
AI
Jan 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tag prefix calculation duplicates the logic from line 66 but is calculated again here. This duplication could lead to maintenance issues if the naming convention changes. Consider reusing the devnet_tag output from the get_labels step instead of recalculating it.
| DEVNET_TAG_PREFIX="$(echo ${{ steps.get_labels.outputs.devnet_label }} | sed 's/^d/D/')" | |
| VERSION="${{ steps.get_labels.outputs.version }}" | |
| DEVNET_TAG_PREFIX="${CURRENT_DEVNET_TAG%-${VERSION}}" |
Copilot
AI
Jan 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The workflow filters tags using version:refname sort, which may not work correctly for tags like "Devnet1", "Devnet2", "Devnet10", etc. This sorting method is designed for semantic version numbers and may produce unexpected results with the "DevnetX" naming convention. For example, "Devnet10" might be sorted before "Devnet2". Consider using a different sorting mechanism or document this limitation.
| LAST_DEVNET_TAG=$(git tag -l "${DEVNET_TAG_PREFIX}*" --sort=-version:refname | grep -v "^$CURRENT_DEVNET_TAG$" | head -n 1) | |
| LAST_DEVNET_TAG=$(git tag -l "${DEVNET_TAG_PREFIX}*" --sort=-creatordate | grep -v "^$CURRENT_DEVNET_TAG$" | head -n 1) |
Copilot
AI
Jan 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The sed substitutions being used here are redundant and incorrect. The pattern 's/ by @/ by @/g' replaces " by @" with " by @" (same text), and 's/ in / in #/g' replaces " in " with " in #" which doesn't properly prepend '#' to commit hashes. The intent appears to be formatting the commit hash with '#', but this will result in text like "in #abc123" instead of proper GitHub commit references. Consider using the proper format string in git log or adjusting the sed pattern to correctly format the output.
| # Get commits with author and PR info for GitHub-style format | |
| CHANGELOG=$(git log --oneline --pretty=format:"- %s by @%an in %h" | head -20 | sed 's/ by @/ by @/g' | sed 's/ in / in #/g') | |
| else | |
| echo "ℹ️ Generating changelog from $LAST_DEVNET_TAG to current" | |
| # Get commits between tags with author and PR info | |
| CHANGELOG=$(git log --oneline --pretty=format:"- %s by @%an in %h" $LAST_DEVNET_TAG..HEAD | sed 's/ by @/ by @/g' | sed 's/ in / in #/g') | |
| # Get commits with author and hash info for GitHub-style format | |
| CHANGELOG=$(git log --oneline --pretty=format:"- %s by @%an in %h" | head -20) | |
| else | |
| echo "ℹ️ Generating changelog from $LAST_DEVNET_TAG to current" | |
| # Get commits between tags with author and hash info | |
| CHANGELOG=$(git log --oneline --pretty=format:"- %s by @%an in %h" $LAST_DEVNET_TAG..HEAD) |
Copilot
AI
Jan 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue as line 136 - the sed substitutions are redundant and incorrect. The pattern 's/ by @/ by @/g' doesn't change anything, and 's/ in / in #/g' doesn't properly format commit references for GitHub.
| # Get commits with author and PR info for GitHub-style format | |
| CHANGELOG=$(git log --oneline --pretty=format:"- %s by @%an in %h" | head -20 | sed 's/ by @/ by @/g' | sed 's/ in / in #/g') | |
| else | |
| echo "ℹ️ Generating changelog from $LAST_DEVNET_TAG to current" | |
| # Get commits between tags with author and PR info | |
| CHANGELOG=$(git log --oneline --pretty=format:"- %s by @%an in %h" $LAST_DEVNET_TAG..HEAD | sed 's/ by @/ by @/g' | sed 's/ in / in #/g') | |
| # Get commits with author and commit info for GitHub-style format | |
| CHANGELOG=$(git log --oneline --pretty=format:"- %s by @%an in %h" | head -20) | |
| else | |
| echo "ℹ️ Generating changelog from $LAST_DEVNET_TAG to current" | |
| # Get commits between tags with author and commit info | |
| CHANGELOG=$(git log --oneline --pretty=format:"- %s by @%an in %h" $LAST_DEVNET_TAG..HEAD) |
Copilot
AI
Jan 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The heredoc (lines 149-164) uses variable interpolation with GitHub Actions expressions like ${{ steps.get_labels.outputs.devnet_label }}. However, if the CHANGELOG variable contains special characters or formatting, it could break the heredoc structure or produce unexpected output. Consider using a different approach to write the release notes, such as using proper quoting or writing the file programmatically with echo statements that properly escape content.
| ${CHANGELOG} | |
| EOF | |
| # Append the changelog content safely without further shell expansion | |
| printf '%s\n' "$CHANGELOG" >> release_notes.md | |
| printf '\n' >> release_notes.md | |
| cat >> release_notes.md << EOF |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The workflow extracts label data using jq on JSON that includes user-controlled PR labels. While the current regex patterns provide some validation, if a malicious user creates a label that matches the version or devnet patterns but contains additional shell metacharacters, it could potentially cause issues. The current regex patterns (^[0-9]+\.[0-9]+\.[0-9]+$ and ^devnet[0-9]+$) are strict enough to prevent shell injection, but consider adding explicit validation that the extracted values contain only expected characters before using them in git commands and other shell operations.