Skip to content

Commit 462e98e

Browse files
authored
Merge branch 'main' into gov-support
2 parents dffeae9 + 29b0115 commit 462e98e

37 files changed

Lines changed: 4024 additions & 55 deletions
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
# .github/workflows/breaking-change-check.yml
2+
#
3+
# Analyzes every PR that touches src/bedrock_agentcore/ for public API
4+
# breaking changes and posts a comment on the PR with the results.
5+
#
6+
# Uses griffe (https://mkdocstrings.github.io/griffe/) — the standard Python
7+
# library for static API analysis, used by mkdocstrings, Rye, and others.
8+
# It understands __all__, class hierarchies, decorators, multi-line signatures,
9+
# and parameter kind changes — far beyond what git-diff heuristics can detect.
10+
#
11+
# This workflow is INFORMATIONAL ONLY. It never blocks a merge.
12+
# Intended use: reviewer awareness for breaking changes that may need a
13+
# CHANGELOG entry or a deprecation notice before removal.
14+
#
15+
16+
name: Breaking Change Check
17+
18+
on:
19+
pull_request:
20+
branches: [main]
21+
paths:
22+
- 'src/bedrock_agentcore/**'
23+
24+
permissions:
25+
contents: read # checkout
26+
pull-requests: write # post/update PR comment
27+
28+
jobs:
29+
check-breaking-changes:
30+
name: Detect Breaking Changes
31+
runs-on: ubuntu-latest
32+
33+
steps:
34+
- name: Checkout PR
35+
uses: actions/checkout@v6
36+
with:
37+
# Full history needed so griffe can create a worktree at the base ref.
38+
fetch-depth: 0
39+
40+
- name: Set up Python
41+
uses: actions/setup-python@v6
42+
with:
43+
python-version: '3.10'
44+
45+
- name: Install griffe
46+
run: pip install griffe
47+
48+
# Fetch the base branch so the ref is available for griffe's worktree.
49+
- name: Fetch base branch
50+
run: git fetch origin "${{ github.base_ref }}" --depth=1
51+
52+
# Run griffe using its Python API for stable, structured output.
53+
# The Python API is used instead of the CLI to:
54+
# a) get markdown-formatted output for the PR comment
55+
# b) handle errors gracefully without failing the job
56+
# c) avoid relying on CLI flag stability across griffe versions
57+
#
58+
# Exit codes written to GITHUB_OUTPUT:
59+
# exit_code=0 → no breaking changes
60+
# exit_code=1 → breaking changes found
61+
# exit_code=2 → griffe itself errored (treated as a warning, not a failure)
62+
- name: Run griffe analysis
63+
id: griffe
64+
env:
65+
BASE_REF: ${{ github.base_ref }}
66+
run: |
67+
python3 - <<'PYEOF'
68+
import griffe, sys, os
69+
70+
search = ["src"]
71+
base_ref = f"origin/{os.environ['BASE_REF']}"
72+
73+
# Load the old API from the base branch via a temporary git worktree.
74+
# Load the new API from the current working tree (the PR branch).
75+
try:
76+
old = griffe.load_git("bedrock_agentcore", ref=base_ref, search_paths=search)
77+
new = griffe.load("bedrock_agentcore", search_paths=search)
78+
except griffe.GitError as e:
79+
print(f"::warning::griffe could not create worktree for {base_ref}: {e}")
80+
print(f"::warning::Skipping breaking change analysis for this PR.")
81+
# Write a neutral comment and exit cleanly — don't block the job.
82+
with open("/tmp/breaking-changes.md", "w") as f:
83+
f.write(
84+
"## ℹ️ Breaking Change Analysis Skipped\n\n"
85+
"griffe could not load the base branch for comparison. "
86+
"This is usually a transient git issue. "
87+
"A maintainer can re-run this check manually."
88+
)
89+
with open(os.environ["GITHUB_OUTPUT"], "a") as out:
90+
out.write("exit_code=2\n")
91+
sys.exit(0)
92+
except Exception as e:
93+
print(f"::warning::griffe analysis failed unexpectedly: {e}")
94+
with open("/tmp/breaking-changes.md", "w") as f:
95+
f.write(
96+
"## ℹ️ Breaking Change Analysis Skipped\n\n"
97+
f"griffe encountered an unexpected error: `{e}`"
98+
)
99+
with open(os.environ["GITHUB_OUTPUT"], "a") as out:
100+
out.write("exit_code=2\n")
101+
sys.exit(0)
102+
103+
breakages = list(griffe.find_breaking_changes(old, new))
104+
105+
if not breakages:
106+
body = (
107+
"## ✅ No Breaking Changes Detected\n\n"
108+
"No public API breaking changes found in this PR."
109+
)
110+
with open("/tmp/breaking-changes.md", "w") as f:
111+
f.write(body)
112+
with open(os.environ["GITHUB_OUTPUT"], "a") as out:
113+
out.write("exit_code=0\n")
114+
print("✓ No breaking changes detected.")
115+
sys.exit(0)
116+
117+
# Format output as markdown for the PR comment.
118+
lines = [
119+
"## ⚠️ Breaking Change Warning",
120+
"",
121+
f"Found **{len(breakages)}** potential breaking change(s) in this PR:",
122+
"",
123+
]
124+
for b in breakages:
125+
lines.append(b.explain(style=griffe.ExplanationStyle.markdown))
126+
127+
lines += [
128+
"",
129+
"---",
130+
"> **Note:** This is an automated static analysis check. "
131+
"Some flagged changes may be intentional.",
132+
"> Please confirm each item is expected and, if so, add a migration note to `CHANGELOG.md`.",
133+
]
134+
135+
body = "\n".join(lines)
136+
with open("/tmp/breaking-changes.md", "w") as f:
137+
f.write(body)
138+
139+
with open(os.environ["GITHUB_OUTPUT"], "a") as out:
140+
out.write("exit_code=1\n")
141+
142+
print(f"⚠️ {len(breakages)} breaking change(s) found.")
143+
# Exit 0 here — the job itself always succeeds (informational).
144+
# The PR comment carries the signal; the job status does not block merge.
145+
sys.exit(0)
146+
PYEOF
147+
148+
# Post or update a single persistent comment on the PR.
149+
# Uses a hidden HTML marker so subsequent pushes update the same comment
150+
# rather than creating a new one per commit.
151+
- name: Post or update PR comment
152+
uses: actions/github-script@v8
153+
with:
154+
script: |
155+
const fs = require('fs');
156+
const body = fs.readFileSync('/tmp/breaking-changes.md', 'utf8');
157+
158+
// Marker that identifies the comment as ours for future updates.
159+
const marker = '<!-- breaking-change-check -->';
160+
const fullBody = `${marker}\n${body}`;
161+
162+
const { data: comments } = await github.rest.issues.listComments({
163+
owner: context.repo.owner,
164+
repo: context.repo.repo,
165+
issue_number: context.payload.pull_request.number,
166+
});
167+
168+
const existing = comments.find(c => c.body.includes(marker));
169+
170+
if (existing) {
171+
await github.rest.issues.updateComment({
172+
owner: context.repo.owner,
173+
repo: context.repo.repo,
174+
comment_id: existing.id,
175+
body: fullBody,
176+
});
177+
console.log(`Updated existing breaking change comment (id: ${existing.id})`);
178+
} else {
179+
await github.rest.issues.createComment({
180+
owner: context.repo.owner,
181+
repo: context.repo.repo,
182+
issue_number: context.payload.pull_request.number,
183+
body: fullBody,
184+
});
185+
console.log('Created new breaking change comment');
186+
}
187+
188+
// Log summary to the Actions step output for visibility.
189+
const exitCode = '${{ steps.griffe.outputs.exit_code }}';
190+
if (exitCode === '1') {
191+
core.warning('Breaking changes detected — see PR comment for details.');
192+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# .github/workflows/dependabot-auto-merge.yml
2+
#
3+
# Automatically enables auto-merge on Dependabot PRs for minor and patch
4+
# version bumps. GitHub holds the actual merge until all required status
5+
# checks in the 'main-status-checks' Ruleset pass.
6+
#
7+
# Major version bumps are explicitly skipped and require human review
8+
# from the aws/bedrock-agentcore-maintainers team.
9+
#
10+
# PREREQUISITES (already completed):
11+
# ✅ Ruleset 'main-status-checks' — CI must pass, no bypass for anyone
12+
# ✅ Ruleset 'main' — approval requirement, Dependabot bypass added
13+
# ✅ Settings → General → Allow auto-merge enabled
14+
15+
name: Dependabot Auto-merge
16+
17+
on:
18+
pull_request:
19+
types: [opened, synchronize, reopened, ready_for_review]
20+
21+
permissions:
22+
contents: write # required to execute the squash merge
23+
pull-requests: write # required to enable auto-merge
24+
25+
jobs:
26+
dependabot-auto-merge:
27+
name: Auto-merge minor/patch PRs
28+
runs-on: ubuntu-latest
29+
30+
# Only act on PRs opened by the Dependabot bot.
31+
# The correct login is 'dependabot[bot]' — the bare string 'dependabot'
32+
# never matches and would silently skip all runs.
33+
if: github.actor == 'dependabot[bot]'
34+
35+
steps:
36+
- name: Fetch Dependabot metadata
37+
id: metadata
38+
uses: dependabot/fetch-metadata@v2
39+
with:
40+
github-token: ${{ secrets.GITHUB_TOKEN }}
41+
42+
# patch and minor bumps: enable auto-merge.
43+
# GitHub holds the merge until all required status checks pass.
44+
# If CI fails the PR stays open — no merge happens.
45+
- name: Enable auto-merge for minor/patch bumps
46+
if: |
47+
steps.metadata.outputs.update-type == 'version-update:semver-patch' ||
48+
steps.metadata.outputs.update-type == 'version-update:semver-minor'
49+
env:
50+
PR_URL: ${{ github.event.pull_request.html_url }}
51+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
52+
run: |
53+
gh pr merge --auto --squash "$PR_URL"
54+
echo "✓ Auto-merge enabled: ${{ steps.metadata.outputs.dependency-names }} \
55+
(${{ steps.metadata.outputs.previous-version }} → \
56+
${{ steps.metadata.outputs.new-version }}, \
57+
${{ steps.metadata.outputs.update-type }})"
58+
59+
# major bumps: log clearly and do nothing.
60+
# The PR stays open and is assigned to aws/bedrock-agentcore-maintainers
61+
# via dependabot.yml for human review.
62+
- name: Skip major bumps — human review required
63+
if: steps.metadata.outputs.update-type == 'version-update:semver-major'
64+
run: |
65+
echo "⏭ Skipped: ${{ steps.metadata.outputs.dependency-names }} \
66+
is a major bump (${{ steps.metadata.outputs.previous-version }} → \
67+
${{ steps.metadata.outputs.new-version }}). \
68+
Requires review from aws/bedrock-agentcore-maintainers."

0 commit comments

Comments
 (0)