Skip to content

Commit 482f4bd

Browse files
authored
Merge branch 'main' into copilot/allow-custom-formatter-toolresultcompactionstrateg
2 parents 4812d2f + 052ba7b commit 482f4bd

File tree

129 files changed

+8284
-1493
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

129 files changed

+8284
-1493
lines changed
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
# Probe the highest allowed dependency versions, then open issues/PRs from the passing updates.
2+
name: Python - Dependency Range Validation
3+
4+
on:
5+
workflow_dispatch:
6+
7+
permissions:
8+
contents: write
9+
issues: write
10+
pull-requests: write
11+
12+
env:
13+
UV_CACHE_DIR: /tmp/.uv-cache
14+
15+
jobs:
16+
dependency-range-validation:
17+
name: Dependency Range Validation
18+
runs-on: ubuntu-latest
19+
env:
20+
# For now only run 3.13, if we do encounter situations where there are mismatches between packages and python versions (other then 3.10 and 3.14 which are known to not be able to install everything)
21+
# then we will have to reevaluate.
22+
UV_PYTHON: "3.13"
23+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24+
steps:
25+
- uses: actions/checkout@v6
26+
with:
27+
fetch-depth: 0
28+
29+
- name: Set up python and install the project
30+
uses: ./.github/actions/python-setup
31+
with:
32+
python-version: ${{ env.UV_PYTHON }}
33+
os: ${{ runner.os }}
34+
env:
35+
UV_CACHE_DIR: /tmp/.uv-cache
36+
37+
- name: Run dependency range validation
38+
id: validate_ranges
39+
# Keep workflow running so we can still publish diagnostics from this run.
40+
continue-on-error: true
41+
run: uv run poe validate-dependency-bounds-project --mode upper --project "*"
42+
working-directory: ./python
43+
44+
- name: Upload dependency range report
45+
# Always publish the report so failures are inspectable even when validation fails.
46+
if: always()
47+
uses: actions/upload-artifact@v4
48+
with:
49+
name: dependency-range-results
50+
path: python/scripts/dependencies/dependency-range-results.json
51+
if-no-files-found: warn
52+
53+
- name: Create issues for failed dependency candidates
54+
# Always process the report so failed candidates create actionable tracking issues.
55+
if: always()
56+
uses: actions/github-script@v8
57+
with:
58+
script: |
59+
const fs = require("fs")
60+
const reportPath = "python/scripts/dependencies/dependency-range-results.json"
61+
62+
if (!fs.existsSync(reportPath)) {
63+
core.warning(`No dependency range report found at ${reportPath}`)
64+
return
65+
}
66+
67+
const report = JSON.parse(fs.readFileSync(reportPath, "utf8"))
68+
const dependencyFailures = []
69+
70+
for (const packageResult of report.packages ?? []) {
71+
for (const dependency of packageResult.dependencies ?? []) {
72+
const candidateVersions = new Set(dependency.candidate_versions ?? [])
73+
const failedAttempts = (dependency.attempts ?? []).filter(
74+
(attempt) => attempt.status === "failed" && candidateVersions.has(attempt.trial_upper)
75+
)
76+
if (!failedAttempts.length) {
77+
continue
78+
}
79+
80+
const failuresByVersion = new Map()
81+
for (const attempt of failedAttempts) {
82+
const version = attempt.trial_upper || "unknown"
83+
if (!failuresByVersion.has(version)) {
84+
failuresByVersion.set(version, attempt.error || "No error output captured.")
85+
}
86+
}
87+
88+
dependencyFailures.push({
89+
packageName: packageResult.package_name,
90+
projectPath: packageResult.project_path,
91+
dependencyName: dependency.name,
92+
originalRequirements: dependency.original_requirements ?? [],
93+
finalRequirements: dependency.final_requirements ?? [],
94+
failedVersions: [...failuresByVersion.entries()].map(([version, error]) => ({ version, error })),
95+
})
96+
}
97+
}
98+
99+
if (!dependencyFailures.length) {
100+
core.info("No failing dependency candidates found.")
101+
return
102+
}
103+
104+
const owner = context.repo.owner
105+
const repo = context.repo.repo
106+
const openIssues = await github.paginate(github.rest.issues.listForRepo, {
107+
owner,
108+
repo,
109+
state: "open",
110+
per_page: 100,
111+
})
112+
const openIssueTitles = new Set(
113+
openIssues.filter((issue) => !issue.pull_request).map((issue) => issue.title)
114+
)
115+
116+
const formatError = (message) => String(message || "No error output captured.").replace(/```/g, "'''")
117+
118+
for (const failure of dependencyFailures) {
119+
const title = `Dependency validation failed: ${failure.dependencyName} (${failure.packageName})`
120+
if (openIssueTitles.has(title)) {
121+
core.info(`Issue already exists: ${title}`)
122+
continue
123+
}
124+
125+
const visibleFailures = failure.failedVersions.slice(0, 5)
126+
const omittedCount = failure.failedVersions.length - visibleFailures.length
127+
const failureDetails = visibleFailures
128+
.map(
129+
(entry) =>
130+
`- \`${entry.version}\`\n\n\`\`\`\n${formatError(entry.error).slice(0, 3500)}\n\`\`\``
131+
)
132+
.join("\n\n")
133+
134+
const body = [
135+
"Automated dependency range validation found candidate versions that failed checks.",
136+
"",
137+
`- Package: \`${failure.packageName}\``,
138+
`- Project path: \`${failure.projectPath}\``,
139+
`- Dependency: \`${failure.dependencyName}\``,
140+
`- Original requirements: ${
141+
failure.originalRequirements.length
142+
? failure.originalRequirements.map((value) => `\`${value}\``).join(", ")
143+
: "_none_"
144+
}`,
145+
`- Final requirements after run: ${
146+
failure.finalRequirements.length
147+
? failure.finalRequirements.map((value) => `\`${value}\``).join(", ")
148+
: "_none_"
149+
}`,
150+
"",
151+
"### Failed versions and errors",
152+
failureDetails,
153+
omittedCount > 0 ? `\n_Additional failed versions omitted: ${omittedCount}_` : "",
154+
"",
155+
`Workflow run: ${context.serverUrl}/${owner}/${repo}/actions/runs/${context.runId}`,
156+
].join("\n")
157+
158+
await github.rest.issues.create({
159+
owner,
160+
repo,
161+
title,
162+
body,
163+
})
164+
openIssueTitles.add(title)
165+
core.info(`Created issue: ${title}`)
166+
}
167+
168+
- name: Refresh lockfile
169+
# Only refresh lockfile after a clean validation to avoid committing known-bad ranges.
170+
if: steps.validate_ranges.outcome == 'success'
171+
run: uv lock --upgrade
172+
working-directory: ./python
173+
174+
- name: Commit and push dependency updates
175+
id: commit_updates
176+
if: steps.validate_ranges.outcome == 'success'
177+
run: |
178+
BRANCH="automation/python-dependency-range-updates"
179+
180+
git config user.name "github-actions[bot]"
181+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
182+
git checkout -B "${BRANCH}"
183+
184+
git add python/packages/*/pyproject.toml python/uv.lock
185+
if git diff --cached --quiet; then
186+
echo "has_changes=false" >> "$GITHUB_OUTPUT"
187+
echo "No dependency updates to commit."
188+
exit 0
189+
fi
190+
191+
git commit -m "chore: update dependency ranges"
192+
git push --force-with-lease --set-upstream origin "${BRANCH}"
193+
echo "has_changes=true" >> "$GITHUB_OUTPUT"
194+
195+
- name: Create or update pull request with GitHub CLI
196+
# Only open/update PRs for validated updates to keep automation branches trustworthy.
197+
if: steps.validate_ranges.outcome == 'success' && steps.commit_updates.outputs.has_changes == 'true'
198+
run: |
199+
BRANCH="automation/python-dependency-range-updates"
200+
PR_TITLE="Python: chore: update dependency ranges"
201+
PR_BODY_FILE="$(mktemp)"
202+
203+
cat > "${PR_BODY_FILE}" <<'EOF'
204+
This PR was generated by the dependency range validation workflow.
205+
206+
- Ran `uv run poe validate-dependency-bounds-project --mode upper --project "*"`
207+
- Updated package dependency bounds
208+
- Refreshed `python/uv.lock` with `uv lock --upgrade`
209+
EOF
210+
211+
PR_NUMBER="$(gh pr list --head "${BRANCH}" --base main --state open --json number --jq '.[0].number')"
212+
if [ -n "${PR_NUMBER}" ]; then
213+
gh pr edit "${PR_NUMBER}" --title "${PR_TITLE}" --body-file "${PR_BODY_FILE}"
214+
else
215+
gh pr create --base main --head "${BRANCH}" --title "${PR_TITLE}" --body-file "${PR_BODY_FILE}"
216+
fi
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
name: Python - Dev Dependency Upgrade
2+
3+
on:
4+
workflow_dispatch:
5+
6+
permissions:
7+
contents: write
8+
pull-requests: write
9+
10+
env:
11+
UV_CACHE_DIR: /tmp/.uv-cache
12+
13+
jobs:
14+
upgrade-dev-dependencies:
15+
name: Upgrade Dev Dependencies
16+
runs-on: ubuntu-latest
17+
env:
18+
UV_PYTHON: "3.13"
19+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
20+
steps:
21+
- uses: actions/checkout@v6
22+
with:
23+
fetch-depth: 0
24+
25+
- name: Set up python and install the project
26+
uses: ./.github/actions/python-setup
27+
with:
28+
python-version: ${{ env.UV_PYTHON }}
29+
os: ${{ runner.os }}
30+
env:
31+
UV_CACHE_DIR: /tmp/.uv-cache
32+
33+
- name: Upgrade dev dependencies and validate workspace
34+
run: uv run poe upgrade-dev-dependencies
35+
working-directory: ./python
36+
37+
- name: Commit and push dev dependency updates
38+
id: commit_updates
39+
run: |
40+
BRANCH="automation/python-dev-dependency-updates"
41+
42+
git config user.name "github-actions[bot]"
43+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
44+
git checkout -B "${BRANCH}"
45+
46+
git add python/pyproject.toml python/packages/*/pyproject.toml python/uv.lock
47+
if git diff --cached --quiet; then
48+
echo "has_changes=false" >> "$GITHUB_OUTPUT"
49+
echo "No dev dependency updates to commit."
50+
exit 0
51+
fi
52+
53+
git commit -F- <<'EOF'
54+
Python: chore: upgrade dev dependencies
55+
EOF
56+
git push --force-with-lease --set-upstream origin "${BRANCH}"
57+
echo "has_changes=true" >> "$GITHUB_OUTPUT"
58+
59+
- name: Create or update pull request with GitHub CLI
60+
if: steps.commit_updates.outputs.has_changes == 'true'
61+
run: |
62+
BRANCH="automation/python-dev-dependency-updates"
63+
PR_TITLE="Python: chore: upgrade dev dependencies"
64+
PR_BODY_FILE="$(mktemp)"
65+
66+
cat > "${PR_BODY_FILE}" <<'EOF'
67+
### Motivation and Context
68+
69+
This automated update refreshes Python dev dependency pins across the workspace and reruns the repo validation gates before opening a pull request.
70+
71+
### Description
72+
73+
- Ran `uv run poe upgrade-dev-dependencies`
74+
- Refreshed dev dependency pins in workspace `pyproject.toml` files
75+
- Refreshed `python/uv.lock` with `uv lock --upgrade`
76+
- Reinstalled from the frozen lockfile and reran `check`, `typing`, and `test`
77+
78+
### Contribution Checklist
79+
80+
- [x] The code builds clean without any errors or warnings
81+
- [x] The PR follows the [Contribution Guidelines](https://github.com/microsoft/agent-framework/blob/main/CONTRIBUTING.md)
82+
- [x] All unit tests pass, and I have added new tests where possible
83+
- [ ] **Is this a breaking change?** If yes, add "[BREAKING]" prefix to the title of the PR.
84+
EOF
85+
86+
PR_NUMBER="$(gh pr list --head "${BRANCH}" --base main --state open --json number --jq '.[0].number')"
87+
if [ -n "${PR_NUMBER}" ]; then
88+
gh pr edit "${PR_NUMBER}" --title "${PR_TITLE}" --body-file "${PR_BODY_FILE}"
89+
else
90+
gh pr create --base main --head "${BRANCH}" --title "${PR_TITLE}" --body-file "${PR_BODY_FILE}"
91+
fi

.github/workflows/python-lab-tests.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ jobs:
7676
- name: Run lab tests
7777
run: cd packages/lab && uv run poe test
7878

79+
- name: Run resource-intensive lab tests
80+
run: cd packages/lab && uv run pytest -m "resource_intensive and not integration" --junitxml=test-results-resource-intensive.xml
81+
7982
- name: Run lab lint
8083
run: cd packages/lab && uv run poe lint
8184

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,9 @@ WARP.md
205205
**/memory-bank/
206206
**/projectBrief.md
207207
**/tmpclaude*
208+
# Dependency-bound validation reports
209+
python/scripts/dependency-*-results.json
210+
python/scripts/dependencies/dependency-*-results.json
208211

209212
# Azurite storage emulator files
210213
*/__azurite_db_blob__.json*

0 commit comments

Comments
 (0)