-
Notifications
You must be signed in to change notification settings - Fork 15
maintenance/maint release utils #652
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 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,32 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: Guardrail Push Alerts | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| on: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| push: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| branches: [main] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jobs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| slack-alert: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| permissions: {} # Explicitly drops all token permissions | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: github.actor != 'dependabot[bot]' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Process and Format Slack Alert | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SLACK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Safely map variables as structured environment inputs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| COMMIT_MSG: ${{ github.event.head_commit.message }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| COMMITTER: ${{ github.event.head_commit.committer.name }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| REPO_NAME: ${{ github.repository }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ACTOR: ${{ github.actor }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # If the committer isn't 'GitHub', an admin pushed directly via local CLI. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ "$COMMITTER" != "GitHub" ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Use jq to format a completely safe, escaped JSON object for Slack | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PAYLOAD=$(jq -n \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --arg msg "$COMMIT_MSG" \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --arg repo "$REPO_NAME" \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --arg actor "$ACTOR" \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| '{"text": "⚠️ *Direct Push to Main Detected!*\n*Repo:* `\($repo)`\n*Actor:* `@\($actor)`\n*Commit:* `\($msg)`"}') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+25
to
+29
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial | 💤 Low value Line 29 exceeds yamllint's 120-char limit (127 chars). Split the - PAYLOAD=$(jq -n \
- --arg msg "$COMMIT_MSG" \
- --arg repo "$REPO_NAME" \
- --arg actor "$ACTOR" \
- '{"text": "⚠️ *Direct Push to Main Detected!*\n*Repo:* `\($repo)`\n*Actor:* `@\($actor)`\n*Commit:* `\($msg)`"}')
+ PAYLOAD=$(jq -n \
+ --arg msg "$COMMIT_MSG" \
+ --arg repo "$REPO_NAME" \
+ --arg actor "$ACTOR" \
+ '{"text": "⚠️ *Direct Push to Main Detected!*\n*Repo:* `\($repo)`\n*Actor:* `@\($actor)`\n*Commit:* `\($msg | .[0:100])`"}')Actually, the cleaner fix is just to break the string literal—but since 🧰 Tools🪛 GitHub Check: yaml-check[warning] 29-29: 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| curl -X POST -H 'Content-type: application/json' --data "$PAYLOAD" "$SLACK_URL" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+20
to
+32
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider adding a guard for missing If the secret isn't configured in a new repo, this will fail silently (or run: |
+ if [ -z "$SLACK_URL" ]; then
+ echo "::warning::SLACK_WEBHOOK_URL secret is not configured - skipping alert"
+ exit 0
+ fi
# If the committer isn't 'GitHub', an admin pushed directly via local CLI.Also, kudos on using 📝 Committable suggestion
Suggested change
🧰 Tools🪛 GitHub Check: yaml-check[warning] 29-29: 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,159 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| echo "==================================================" | ||
| echo "ACTION TIER CHANGE DETECTION" | ||
| echo "==================================================" | ||
|
|
||
| # 1. Find all action repositories | ||
| ACTION_REPOS=() | ||
| for dir in actions/*; do | ||
| [ -d "$dir" ] || continue | ||
| [ -f "$dir/action.yaml" ] || continue | ||
| ACTION_REPOS+=("${dir#actions/}") | ||
| done | ||
|
|
||
| # 2. Determine dependencies for each repo | ||
| declare -A DEPENDENCIES | ||
| declare -A TIERS | ||
|
|
||
| for repo in "${ACTION_REPOS[@]}"; do | ||
| # Extract dependencies on Framework-R-D/action-* | ||
| # Format: Framework-R-D/action-NAME@SHA # vVERSION | ||
| # We want the NAME part. | ||
| DEPS=$(grep "uses: Framework-R-D/action-" "actions/$repo/action.yaml" | sed -E 's/.*Framework-R-D\/action-([^@ ]+).*/\1/' || true) | ||
| DEPENDENCIES["$repo"]="$DEPS" | ||
| done | ||
|
|
||
| # 3. Iteratively assign tiers | ||
| UNASSIGNED=("${ACTION_REPOS[@]}") | ||
| CURRENT_TIER=1 | ||
|
|
||
| while [ ${#UNASSIGNED[@]} -gt 0 ]; do | ||
| TIER_REPOS=() | ||
| STILL_UNASSIGNED=() | ||
|
|
||
| for repo in "${UNASSIGNED[@]}"; do | ||
| CAN_ASSIGN=true | ||
| for dep in ${DEPENDENCIES["$repo"]}; do | ||
| # If dep is an action repo and not yet assigned a tier, we can't assign this repo yet | ||
| if [[ " ${ACTION_REPOS[*]} " == *" $dep "* ]] && [ -z "${TIERS["$dep"]:-}" ]; then | ||
| CAN_ASSIGN=false | ||
| break | ||
| fi | ||
| done | ||
|
|
||
| if [ "$CAN_ASSIGN" = true ]; then | ||
| TIER_REPOS+=("$repo") | ||
| else | ||
| STILL_UNASSIGNED+=("$repo") | ||
| fi | ||
| done | ||
|
|
||
| if [ ${#TIER_REPOS[@]} -eq 0 ]; then | ||
| echo "❌ Error: Circular dependency detected among: ${STILL_UNASSIGNED[*]}" | ||
| exit 1 | ||
| fi | ||
|
|
||
| for repo in "${TIER_REPOS[@]}"; do | ||
| TIERS["$repo"]=$CURRENT_TIER | ||
| done | ||
|
|
||
| UNASSIGNED=("${STILL_UNASSIGNED[@]}") | ||
| ((CURRENT_TIER++)) | ||
| done | ||
|
|
||
| # Pre-calculate latest tags and change status for all action repos to avoid redundant git calls | ||
| declare -A LATEST_TAGS | ||
| declare -A HAS_CHANGES | ||
| declare -A UNCOMMITTED | ||
|
|
||
| for repo in "${ACTION_REPOS[@]}"; do | ||
| ( | ||
| cd "actions/$repo" || exit 1 | ||
| git fetch --tags -q | ||
| TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "NONE") | ||
| echo "TAG=$TAG" | ||
| if [ "$TAG" != "NONE" ]; then | ||
| CHANGES=$(git log "${TAG}..HEAD" --oneline -- action.yaml 2>/dev/null || echo "") | ||
| if [ -n "$CHANGES" ]; then | ||
| echo "CHANGES=YES" | ||
| else | ||
| echo "CHANGES=NO" | ||
| fi | ||
| else | ||
| echo "CHANGES=NONE" | ||
| fi | ||
|
|
||
| UNCOMMITTED_STATUS=$(git status --porcelain 2>/dev/null || echo "") | ||
| if [ -n "$UNCOMMITTED_STATUS" ]; then | ||
| echo "UNCOMMITTED=YES" | ||
| else | ||
| echo "UNCOMMITTED=NO" | ||
| fi | ||
| ) > "actions/.tmp_${repo}_status" | ||
| done | ||
|
|
||
| # Load the pre-calculated data | ||
| for repo in "${ACTION_REPOS[@]}"; do | ||
| source "actions/.tmp_${repo}_status" | ||
| LATEST_TAGS["$repo"]=$TAG | ||
| HAS_CHANGES["$repo"]=$CHANGES | ||
| UNCOMMITTED["$repo"]=$UNCOMMITTED | ||
| rm "actions/.tmp_${repo}_status" | ||
| done | ||
|
|
||
| # 4. Analyze each tier | ||
| for ((tier=1; tier < CURRENT_TIER; tier++)); do | ||
| echo "--- Tier $tier ---" | ||
|
|
||
| for repo in "${ACTION_REPOS[@]}"; do | ||
| if [ "${TIERS["$repo"]:-}" -eq "$tier" ]; then | ||
| TAG=${LATEST_TAGS["$repo"]} | ||
| CHANGE_STATUS=${HAS_CHANGES["$repo"]} | ||
|
|
||
| if [ "$TAG" = "NONE" ]; then | ||
| echo "📌 REPO: $repo (No tags found)" | ||
| elif [ "$CHANGE_STATUS" = "YES" ]; then | ||
| echo "🔥 REPO: $repo has unreleased changes since $TAG:" | ||
| ( cd "actions/$repo" && git log "${TAG}..HEAD" --oneline -- action.yaml ) | sed 's/^/ - /' | ||
| else | ||
| echo "✅ REPO: $repo is clean ($TAG matches HEAD)" | ||
| fi | ||
|
|
||
| if [ "${UNCOMMITTED["$repo"]:-}" = "YES" ]; then | ||
| echo " ⚠️ REPO: $repo has uncommitted changes!" | ||
| fi | ||
|
|
||
| # Check dependencies for annotations | ||
| for dep in ${DEPENDENCIES["$repo"]}; do | ||
| if [[ " ${ACTION_REPOS[*]} " == *" $dep "* ]]; then | ||
| # 1. Check if dep has changes | ||
| DEP_CHANGE_STATUS=${HAS_CHANGES["$dep"]} | ||
| if [ "$DEP_CHANGE_STATUS" = "YES" ]; then | ||
| echo " ⚠️ Dependency $dep has unreleased changes!" | ||
| fi | ||
|
|
||
| # 2. Check for version mismatch | ||
| DEP_TAG=${LATEST_TAGS["$dep"]} | ||
| REF_VERSION=$(grep "uses: Framework-R-D/action-$dep" "actions/$repo/action.yaml" | sed -E 's/.*# ([^ ]+).*/\1/' | head -n 1 || true) | ||
| if [ -n "$REF_VERSION" ] && [ "$DEP_TAG" != "NONE" ]; then | ||
| if [ "$(printf '%s\n%s' "$REF_VERSION" "$DEP_TAG" | sort -V | tail -n 1)" != "$REF_VERSION" ]; then | ||
| echo " ⚠️ Dependency $dep is at version $DEP_TAG, but $repo refers to $REF_VERSION" | ||
| fi | ||
| fi | ||
| fi | ||
| done | ||
| fi | ||
| done | ||
| done | ||
|
|
||
| echo "" | ||
| echo "==================================================" | ||
| echo "CHANGELOGS TO UPDATE" | ||
| echo "==================================================" | ||
| for repo in "${ACTION_REPOS[@]}"; do | ||
| if [ "${HAS_CHANGES["$repo"]:-}" = "YES" ]; then | ||
| echo "actions/$repo/CHANGELOG.md" | ||
| fi | ||
| done |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| REPO_DIR="${1:-}" | ||
| if [ -z "$REPO_DIR" ] || [ ! -d "$REPO_DIR" ]; then | ||
| echo "Error: Pass a valid local repository directory name." | ||
| exit 1 | ||
| fi | ||
|
|
||
| cd "$REPO_DIR" | ||
| echo "==================================================" | ||
| echo "EXECUTING AUTOMATED RELEASE FOR: $REPO_DIR" | ||
| echo "==================================================" | ||
|
|
||
| # Ensure workspace tree is clean and synchronized | ||
| git fetch upstream main -q | ||
| git checkout main -q | ||
| git pull --ff-only upstream main -q | ||
|
|
||
| # Ensure CHANGELOG.md is committed before tagging | ||
| if ! git diff --quiet CHANGELOG.md; then | ||
| echo "❌ ERROR: Uncommitted changes detected in CHANGELOG.md." | ||
| echo "Please commit your changelog updates before running the release script." | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Step 1: Determine target version from CHANGELOG.md | ||
| echo "-> Determining target version from CHANGELOG.md..." | ||
| TARGET_VERSION="" | ||
|
|
||
| # Iterate through version headers in CHANGELOG.md in order of appearance | ||
| while read -r line; do | ||
| VERSION=$(echo "$line" | sed 's/^## //; s/ --- .*//') | ||
|
|
||
| # A version is pending if: | ||
| # 1. The tag doesn't exist yet. | ||
| # 2. The tag exists, but the README hasn't been pinned to this version. | ||
| if ! git rev-parse "$VERSION" >/dev/null 2>&1 || ! grep -q " # ${VERSION}$" README.md; then | ||
| TARGET_VERSION="$VERSION" | ||
| break | ||
| fi | ||
| done < <(grep "^## v[0-9]*" CHANGELOG.md) | ||
|
|
||
| if [ -z "$TARGET_VERSION" ]; then | ||
| echo "❌ ERROR: No pending versions found in CHANGELOG.md (all versions tagged and pinned)." | ||
| exit 1 | ||
| fi | ||
|
|
||
| NEXT_VERSION="$TARGET_VERSION" | ||
| echo "-> Target version identified: $NEXT_VERSION" | ||
|
|
||
| # Step 2: Build and push the Annotated Tag | ||
| if ! git rev-parse "$NEXT_VERSION" >/dev/null 2>&1; then | ||
| echo "-> Injecting annotated metadata tag..." | ||
| git tag "$NEXT_VERSION" -m "$NEXT_VERSION - automated dependency cycle release" | ||
| git push upstream "$NEXT_VERSION" -q | ||
| else | ||
| echo "-> Tag $NEXT_VERSION already exists. Skipping." | ||
| fi | ||
|
|
||
| # Step 3: Construct server-side Release notes wrapper | ||
| if ! gh release view "$NEXT_VERSION" >/dev/null 2>&1; then | ||
| echo "-> Publishing GitHub Release notes configuration..." | ||
| gh release create "$NEXT_VERSION" \ | ||
| --title "$NEXT_VERSION - updates" \ | ||
| --generate-notes | ||
| else | ||
| echo "-> GitHub Release $NEXT_VERSION already exists. Skipping." | ||
| fi | ||
|
|
||
| # Step 4: Update README.md usage example block automatically | ||
| echo "-> Calculating immutable SHA signatures..." | ||
| NEW_SHA=$(gh api "repos/{owner}/{repo}/git/ref/tags/${NEXT_VERSION}" --jq .object.sha) | ||
| TYPE=$(gh api "repos/{owner}/{repo}/git/ref/tags/${NEXT_VERSION}" --jq .object.type) | ||
|
|
||
| if [ "$TYPE" = "tag" ]; then | ||
| NEW_SHA=$(gh api "repos/{owner}/{repo}/git/tags/${NEW_SHA}" --jq .object.sha) | ||
| fi | ||
|
|
||
| REPO_FULL_NAME=$(gh repo view --json nameWithOwner --jq '.nameWithOwnership') | ||
|
|
||
| echo "-> Found Target Release SHA: $NEW_SHA" | ||
| echo "-> Modifying local README string tokens..." | ||
|
|
||
| OLD_PATTERN="${REPO_FULL_NAME}@[0-9a-f]\{40\} # v[0-9]*" | ||
| NEW_STRING="${REPO_FULL_NAME}@${NEW_SHA} # ${NEXT_VERSION}" | ||
|
|
||
| if grep -q "$NEW_STRING" README.md; then | ||
| echo "-> README already pinned to $NEXT_VERSION. Skipping commit." | ||
| else | ||
| sed -i "s|${OLD_PATTERN}|${NEW_STRING}|" README.md | ||
|
|
||
| # Commit the updated documentation pin back to main | ||
| git add README.md | ||
| git commit -m "docs: pin README usage example to ${NEXT_VERSION} SHA" -q | ||
| git push upstream main -q | ||
| fi | ||
|
|
||
| echo "🚀 SUCCESS: $NEXT_VERSION is complete and pinned!" |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,85 @@ | ||||||||||||||||||||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| echo "==================================================" | ||||||||||||||||||||||||||||||||||||||
| echo "Cascading Dependabot Check via Dynamic Header PR" | ||||||||||||||||||||||||||||||||||||||
| echo "==================================================" | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then | ||||||||||||||||||||||||||||||||||||||
| echo "❌ Error: This folder is not a git repository." | ||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| if [ ! -f ".github/dependabot.yml" ]; then | ||||||||||||||||||||||||||||||||||||||
| echo "❌ Error: .github/dependabot.yml missing. Cannot scan." | ||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # 1. Dynamically resolve the real remote tracking name (handles upstream vs origin) | ||||||||||||||||||||||||||||||||||||||
| echo "--> Resolving active tracking remote name..." | ||||||||||||||||||||||||||||||||||||||
| REMOTE_NAME=$(git config --get branch."$(git branch --show-current)".remote || true) | ||||||||||||||||||||||||||||||||||||||
| if [ -z "$REMOTE_NAME" ]; then | ||||||||||||||||||||||||||||||||||||||
| REMOTE_NAME=$(git config --get branch.main.remote || true) | ||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||
| if [ -z "$REMOTE_NAME" ]; then | ||||||||||||||||||||||||||||||||||||||
| REMOTE_NAME=$(git remote | head -n 1) | ||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||
| if [ -z "$REMOTE_NAME" ]; then | ||||||||||||||||||||||||||||||||||||||
| echo "❌ ERROR: No git remotes configured in this repository." | ||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||
| echo " Found Remote Tracking Target: $REMOTE_NAME" | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # 2. Dynamically resolve the default branch name BEFORE checking out feature branch | ||||||||||||||||||||||||||||||||||||||
| # This guarantees $DEFAULT_BRANCH is bound and available for the final sync step. | ||||||||||||||||||||||||||||||||||||||
| DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/"$REMOTE_NAME"/HEAD 2>/dev/null | sed "s|refs/remotes/$REMOTE_NAME/||" || echo "main") | ||||||||||||||||||||||||||||||||||||||
| echo " Found Default Branch Target: $DEFAULT_BRANCH" | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # 3. Check out a temporary branch specifically for the trigger | ||||||||||||||||||||||||||||||||||||||
| echo "--> Creating local trigger branch..." | ||||||||||||||||||||||||||||||||||||||
| TRIGGER_BRANCH="automation/trigger-dependabot-$(date +%s)" | ||||||||||||||||||||||||||||||||||||||
| git checkout -b "$TRIGGER_BRANCH" -q | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+38
to
+41
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Local trigger branch is never cleaned up.
Add explicit local branch cleanup after syncing to the default branch: 🧹 Proposed fix to delete the local trigger branch # 9. Sync your default branch cleanly to ensure local tracking matches remote tip
echo "--> Synchronizing local default branch workspace..."
git checkout "$DEFAULT_BRANCH" -q
git pull --ff-only "$REMOTE_NAME" "$DEFAULT_BRANCH" -q
+git branch -D "$TRIGGER_BRANCH" -q 2>/dev/null || true
echo "⚡ SUCCESS: Dependabot has initialized an immediate version check cycle cleanly!"Also applies to: 78-78, 82-83 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # 4. Inject a dynamic timestamp comment at the top of dependabot.yml | ||||||||||||||||||||||||||||||||||||||
| echo "--> Injecting fresh timestamp cache key to dependabot.yml header..." | ||||||||||||||||||||||||||||||||||||||
| TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ") | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Write the new timestamp comment as line 1, then append the original file contents | ||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||
| echo "# Triggered via automation release cycle at: ${TIMESTAMP}" | ||||||||||||||||||||||||||||||||||||||
| cat .github/dependabot.yml | ||||||||||||||||||||||||||||||||||||||
| } > .github/dependabot.yml.tmp | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| mv .github/dependabot.yml.tmp .github/dependabot.yml | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # 5. Commit bypassing pre-commit hooks and GPG code-signing requirements | ||||||||||||||||||||||||||||||||||||||
| git add .github/dependabot.yml | ||||||||||||||||||||||||||||||||||||||
| git commit \ | ||||||||||||||||||||||||||||||||||||||
| --no-verify \ | ||||||||||||||||||||||||||||||||||||||
| --no-gpg-sign \ | ||||||||||||||||||||||||||||||||||||||
| -m "chore: force-trigger contemporaneous dependabot evaluation" -q | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # 6. Push the feature branch to the dynamically identified remote | ||||||||||||||||||||||||||||||||||||||
| git push "$REMOTE_NAME" "$TRIGGER_BRANCH" -q | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # 7. Open a temporary Pull Request to force GitHub's backend to process the file change | ||||||||||||||||||||||||||||||||||||||
| echo "--> Opening short-lived activation Pull Request..." | ||||||||||||||||||||||||||||||||||||||
| PR_URL=$(gh pr create \ | ||||||||||||||||||||||||||||||||||||||
| --title "chore: dynamic version check sweep" \ | ||||||||||||||||||||||||||||||||||||||
| --body "Automated system trigger. Safe to delete." \ | ||||||||||||||||||||||||||||||||||||||
| --head "$TRIGGER_BRANCH") | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| PR_NUMBER=$(echo "$PR_URL" | grep -oE '[0-9]+$') | ||||||||||||||||||||||||||||||||||||||
| echo " PR Opened: #$PR_NUMBER" | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+67
to
+73
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win PR number extraction could fail silently with an unhelpful error. If 🛡️ Proposed defensive check PR_URL=$(gh pr create \
--title "chore: dynamic version check sweep" \
--body "Automated system trigger. Safe to delete." \
--head "$TRIGGER_BRANCH")
PR_NUMBER=$(echo "$PR_URL" | grep -oE '[0-9]+$')
+if [ -z "$PR_NUMBER" ]; then
+ echo "❌ Error: Failed to extract PR number from: $PR_URL"
+ exit 1
+fi
echo " PR Opened: #$PR_NUMBER"📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # 8. Close the PR and delete the remote/local branches instantly | ||||||||||||||||||||||||||||||||||||||
| echo "--> Closing PR and cleaning up remote branch..." | ||||||||||||||||||||||||||||||||||||||
| # gh handles deleting the remote branch and checking back out into your local workspace tracking branch | ||||||||||||||||||||||||||||||||||||||
| gh pr close "$PR_NUMBER" --delete-branch | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # 9. Sync your default branch cleanly to ensure local tracking matches remote tip | ||||||||||||||||||||||||||||||||||||||
| echo "--> Synchronizing local default branch workspace..." | ||||||||||||||||||||||||||||||||||||||
| git checkout "$DEFAULT_BRANCH" -q | ||||||||||||||||||||||||||||||||||||||
| git pull --ff-only "$REMOTE_NAME" "$DEFAULT_BRANCH" -q | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| echo "⚡ SUCCESS: Dependabot has initialized an immediate version check cycle cleanly!" | ||||||||||||||||||||||||||||||||||||||
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.
🧩 Analysis chain
🏁 Script executed:
Repository: Framework-R-D/phlex
Length of output: 45
🏁 Script executed:
Repository: Framework-R-D/phlex
Length of output: 6769
🌐 Web query:
GitHub API PATCH repos allow_auto_merge permission required💡 Result:
To update the allow_auto_merge setting for a repository using the GitHub REST API PATCH /repos/{owner}/{repo} endpoint, the authenticated user must have repository write permissions [1][2][3]. Specifically, the following requirements apply: 1. Permission Level: You must have admin or maintainer access to the repository to successfully perform this update [3]. 2. Authentication: If you are using a fine-grained personal access token or a GitHub App, ensure the token has the necessary repository-level permissions. For fine-grained tokens, the write access to the repository is generally required to modify repository settings [1][2]. 3. API Usage: The PATCH request must include the allow_auto_merge parameter in the body, set to true or false [4][3]. Example request: curl -X PATCH -H "Accept: application/vnd.github+json" -H "Authorization: Bearer " https://api.github.com/repos/OWNER/REPO -d '{"allow_auto_merge":true}' [5][3] Note: This setting enables the ability to use auto-merge within the repository [6]. If you are trying to enable auto-merge on an individual pull request rather than enabling the feature for the entire repository, you must use the GraphQL API mutation enablePullRequestAutoMerge instead [5].
Citations:
🌐 Web query:
GitHub permission scope repository-projects what permissions does it grant💡 Result:
The repository-projects permission scope grants access to interact with GitHub Projects associated with a repository [1]. Specifically, it provides read and write access to repository-level projects [1]. In contexts such as GitHub Codespaces configuration, this permission allows authorized entities to perform operations like viewing, creating, or editing projects linked to that specific repository [1]. While the exact level of access (read vs. write) depends on the specific implementation or configuration, it is generally treated as a distinct permission required to manage project boards and their items within the repository's scope [1]. It is important to note that this scope is distinct from broader project management scopes (such as the general project scope used for organization-wide or user-owned projects) [2][3]. Because repository projects are often treated as distinct resources, repository-projects ensures that automation or applications can manage these specific boards without requiring broader, higher-privilege access to all organization-level or personal projects [2][1].
Citations:
Fix the misleading comment about the permission requirement on line 19.
The comment states
repository-projects: writeis "Required if the token needs to modify repository settings via API," butrepository-projectspermission specifically governs GitHub Projects (kanban boards), not repository administration. According to GitHub's API documentation, the PATCH endpoint forallow_auto_mergerequires admin/maintainer access or repository write permissions—not the Projects scope.This permission likely works in practice because
secrets.GITHUB_TOKENin workflows has elevated permissions, but the comment's explanation is technically inaccurate and will confuse future maintainers. Either correct the comment to explain thatGITHUB_TOKENgrants the necessary access despite the unusual permission name, or explicitly document whyrepository-projects: writeis present if there's a non-obvious reason.🧰 Tools
🪛 zizmor (1.25.2)
[error] 16-16: overly broad permissions (excessive-permissions): actions: write is overly broad at the workflow level
(excessive-permissions)
[error] 17-17: overly broad permissions (excessive-permissions): contents: write is overly broad at the workflow level
(excessive-permissions)
[error] 18-18: overly broad permissions (excessive-permissions): pull-requests: write is overly broad at the workflow level
(excessive-permissions)
[warning] 19-19: overly broad permissions (excessive-permissions): repository-projects: write is overly broad at the workflow level
(excessive-permissions)
[warning] 16-16: permissions without explanatory comments (undocumented-permissions): needs an explanatory comment
(undocumented-permissions)
🤖 Prompt for AI Agents