Skip to content

Auto PR (develop -> main) #217

Auto PR (develop -> main)

Auto PR (develop -> main) #217

Workflow file for this run

name: Auto PR (develop -> main)
on:
workflow_run:
workflows: ["CI"]
types: [completed]
branches: [develop]
permissions:
contents: read
pull-requests: write
models: read
jobs:
auto-pr:
name: Create or Update PR
runs-on: ubuntu-latest
if: >
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.head_branch == 'develop' &&
github.event.workflow_run.event == 'push'
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
ref: develop
fetch-depth: 0
- name: Check for existing PR
id: check-pr
run: |
PR_COUNT=$(gh pr list --base main --head develop --state open --json number --jq 'length')
echo "count=$PR_COUNT" >> $GITHUB_OUTPUT
if [ "$PR_COUNT" -gt 0 ]; then
PR_NUMBER=$(gh pr list --base main --head develop --state open --json number --jq '.[0].number')
echo "number=$PR_NUMBER" >> $GITHUB_OUTPUT
PR_BODY=$(gh pr view "$PR_NUMBER" --json body --jq '.body')
if echo "$PR_BODY" | grep -q "Auto-generated by GitHub Actions"; then
echo "is_auto=true" >> $GITHUB_OUTPUT
else
echo "is_auto=false" >> $GITHUB_OUTPUT
fi
else
echo "is_auto=false" >> $GITHUB_OUTPUT
fi
env:
GH_TOKEN: ${{ github.token }}
- name: Predict semantic-release version
if: steps.check-pr.outputs.count == '0' || steps.check-pr.outputs.is_auto == 'true'
id: version
run: |
git fetch origin main:main 2>/dev/null || true
COMMITS=$(git log main..HEAD --pretty=format:"%s" --no-merges)
BUMP="none"
FEAT_COUNT=0
FIX_COUNT=0
BREAKING=false
while IFS= read -r MSG; do
if echo "$MSG" | grep -qiE 'BREAKING[ -]CHANGE|^[a-z]+(\(.+\))?!:'; then
BREAKING=true
fi
if echo "$MSG" | grep -qE '^feat(\(.+\))?:'; then
FEAT_COUNT=$((FEAT_COUNT + 1))
fi
if echo "$MSG" | grep -qE '^fix(\(.+\))?:'; then
FIX_COUNT=$((FIX_COUNT + 1))
fi
done <<< "$COMMITS"
if [ "$BREAKING" = true ]; then
BUMP="major"
elif [ "$FEAT_COUNT" -gt 0 ]; then
BUMP="minor"
elif [ "$FIX_COUNT" -gt 0 ]; then
BUMP="patch"
fi
# Get current latest tag
CURRENT=$(git describe --tags --abbrev=0 main 2>/dev/null || echo "v0.0.0")
CURRENT="${CURRENT#v}"
IFS='.' read -r CUR_MAJOR CUR_MINOR CUR_PATCH <<< "$CURRENT"
case "$BUMP" in
major) NEXT="$((CUR_MAJOR + 1)).0.0" ;;
minor) NEXT="${CUR_MAJOR}.$((CUR_MINOR + 1)).0" ;;
patch) NEXT="${CUR_MAJOR}.${CUR_MINOR}.$((CUR_PATCH + 1))" ;;
none) NEXT="" ;;
esac
echo "bump=$BUMP" >> $GITHUB_OUTPUT
echo "current=v${CURRENT}" >> $GITHUB_OUTPUT
echo "next=${NEXT:+v$NEXT}" >> $GITHUB_OUTPUT
echo "feat_count=$FEAT_COUNT" >> $GITHUB_OUTPUT
echo "fix_count=$FIX_COUNT" >> $GITHUB_OUTPUT
echo "breaking=$BREAKING" >> $GITHUB_OUTPUT
- name: Analyze changes with AI
if: steps.check-pr.outputs.count == '0' || steps.check-pr.outputs.is_auto == 'true'
id: analyze
run: |
COMMITS=$(git log main..HEAD --pretty=format:"- %s (%h)" --no-merges)
FILES_CHANGED=$(git diff main..HEAD --stat)
BUMP="${{ steps.version.outputs.bump }}"
CURRENT="${{ steps.version.outputs.current }}"
NEXT="${{ steps.version.outputs.next }}"
cat > /tmp/prompt.txt <<PROMPT
Create a pull request title and description for merging develop into main.
Project: OpenVox Operator - a Kubernetes Operator for deploying and managing OpenVox (Puppet) environments on Kubernetes/OpenShift using rootless containers.
Predicted release: ${CURRENT} -> ${NEXT} (${BUMP} bump)
ALL commits since last release (complete list, nothing omitted):
$COMMITS
Files changed (summary):
$FILES_CHANGED
IMPORTANT: The FIRST line of your response must be a concise PR title (max 60 chars, no markdown, no prefix like "Title:"). It should summarize the most important changes. Examples: "Add Database CRD and update CI workflows", "Fix auth handling and bump dependencies".
Then leave one blank line and write the description. You MUST cover ALL commits listed above - do not skip any.
## Summary
- 5-8 bullet points explaining WHAT changed and WHY
## Changes
- Categorized list covering EVERY commit (features, fixes, refactor, chore, docs, tests, ci)
## Testing
- How to verify these changes
PROMPT
REQUEST_JSON=$(jq -n \
--arg system "You are a technical writer creating concise PR descriptions for a Kubernetes Operator project written in Go with Helm charts. Focus on WHY changes were made, not just WHAT changed. Be professional and concise. The very first line of your response MUST be a short PR title without any markdown formatting." \
--arg user "$(cat /tmp/prompt.txt)" \
'{
"messages": [
{"role": "system", "content": $system},
{"role": "user", "content": $user}
],
"model": "gpt-4.1",
"temperature": 0.7,
"max_tokens": 4000
}')
API_RESPONSE=$(echo "$REQUEST_JSON" | curl -s -X POST \
"https://models.inference.ai.azure.com/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${{ github.token }}" \
-d @-)
ANALYSIS=$(echo "$API_RESPONSE" | jq -r '.choices[0].message.content // empty')
if [ -z "$ANALYSIS" ]; then
echo "::warning::AI analysis failed, using fallback description"
ANALYSIS="Release ${NEXT:-develop -> main}
## Changes
$COMMITS
## Files changed
\`\`\`
$FILES_CHANGED
\`\`\`"
fi
echo "$ANALYSIS" > /tmp/pr_description.txt
echo "description_file=/tmp/pr_description.txt" >> $GITHUB_OUTPUT
- name: Build PR title and body
if: steps.check-pr.outputs.count == '0' || steps.check-pr.outputs.is_auto == 'true'
id: pr-content
run: |
BUMP="${{ steps.version.outputs.bump }}"
CURRENT="${{ steps.version.outputs.current }}"
NEXT="${{ steps.version.outputs.next }}"
FEAT_COUNT="${{ steps.version.outputs.feat_count }}"
FIX_COUNT="${{ steps.version.outputs.fix_count }}"
BREAKING="${{ steps.version.outputs.breaking }}"
# Build title from release prediction
if [ "$BUMP" = "none" ]; then
TITLE="Release develop -> main (no release)"
else
TITLE="Release ${NEXT} (${BUMP})"
fi
echo "title=$TITLE" >> $GITHUB_OUTPUT
# Build version badge
if [ "$BUMP" = "none" ]; then
VERSION_INFO="No release-triggering commits detected (chore/ci/docs only)."
else
VERSION_INFO="**Predicted release:** \`${CURRENT}\` -> \`${NEXT}\` (**${BUMP}**)"
DETAILS=""
if [ "$BREAKING" = "true" ]; then
DETAILS="${DETAILS} BREAKING CHANGE detected"
fi
if [ "$FEAT_COUNT" -gt 0 ]; then
DETAILS="${DETAILS} ${FEAT_COUNT} feature(s)"
fi
if [ "$FIX_COUNT" -gt 0 ]; then
DETAILS="${DETAILS} ${FIX_COUNT} fix(es)"
fi
if [ -n "$DETAILS" ]; then
VERSION_INFO="${VERSION_INFO}
${DETAILS}"
fi
fi
# Build body: skip first line (title) from AI output
AI_DESCRIPTION=$(tail -n +2 /tmp/pr_description.txt)
cat > /tmp/pr_body.txt <<EOF
$AI_DESCRIPTION
---
### Release prediction
$VERSION_INFO
---
**Source:** \`develop\` | **Target:** \`main\` | **Trigger:** Successful CI on develop
> Auto-generated by GitHub Actions & AI - updated automatically on new commits.
EOF
- name: Update existing PR
if: steps.check-pr.outputs.count != '0' && steps.check-pr.outputs.is_auto == 'true'
run: |
gh pr edit ${{ steps.check-pr.outputs.number }} \
--title "${{ steps.pr-content.outputs.title }}" \
--body-file /tmp/pr_body.txt
echo "::notice::Updated PR #${{ steps.check-pr.outputs.number }}"
env:
GH_TOKEN: ${{ github.token }}
- name: Create PR
if: steps.check-pr.outputs.count == '0'
run: |
gh pr create \
--title "${{ steps.pr-content.outputs.title }}" \
--body-file /tmp/pr_body.txt \
--base main \
--head develop
env:
GH_TOKEN: ${{ github.token }}