Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions .github/workflows/main-ci-failure-issue.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# .github/workflows/main-ci-failure-issue.yml

name: 'Main CI Failure Issue'

on:
workflow_run:
workflows: ['E2E Tests', 'SDK Python']
types: ['completed']

permissions:
contents: 'read'
issues: 'write'

defaults:
run:
shell: 'bash'

jobs:
create_issue:
name: 'Create autofix issue'
if: "${{ github.repository == 'QwenLM/qwen-code' && github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.head_branch == 'main' && github.event.workflow_run.event == 'push' }}"
runs-on: 'ubuntu-latest'
timeout-minutes: 5
steps:
- name: 'Create autofix-ready issue'
env:
GH_TOKEN: '${{ secrets.CI_DEV_BOT_PAT }}'
REPO: '${{ github.repository }}'
WORKFLOW_NAME: '${{ github.event.workflow_run.name }}'
WORKFLOW_RUN_ID: '${{ github.event.workflow_run.id }}'
WORKFLOW_RUN_URL: '${{ github.event.workflow_run.html_url }}'
HEAD_SHA: '${{ github.event.workflow_run.head_sha }}'
HEAD_BRANCH: '${{ github.event.workflow_run.head_branch }}'
AUTOFIX_BOT: "${{ vars.AUTOFIX_BOT_LOGIN || 'qwen-code-dev-bot' }}"
BUG_LABEL: 'type/bug'
READY_FOR_AGENT_LABEL: 'status/ready-for-agent'
AUTOFIX_APPROVED_LABEL: 'autofix/approved'
run: |-
short_sha="${HEAD_SHA:0:12}"
marker="qwen-main-ci-failure:${HEAD_SHA}"

apply_autofix_route() {
gh issue edit "$1" \
--repo "${REPO}" \
--add-label "${BUG_LABEL},${READY_FOR_AGENT_LABEL},${AUTOFIX_APPROVED_LABEL}" \
--add-assignee "${AUTOFIX_BOT}"
}

existing_issue="$(
gh issue list \
--repo "${REPO}" \
--state open \
--search "${marker} in:body" \
--json number \
--jq '.[0].number // ""'
)"

if [[ -n "${existing_issue}" ]]; then
echo "Issue #${existing_issue} already tracks CI failure for ${HEAD_SHA}."
apply_autofix_route "${existing_issue}"
exit 0
fi

body_file="$(mktemp)"
{
echo "<!-- ${marker} -->"
echo
echo "A main-branch CI run failed on \`${HEAD_BRANCH}\`."
echo
echo "- Workflow: ${WORKFLOW_NAME}"
echo "- Run: ${WORKFLOW_RUN_URL}"
echo "- Run ID: ${WORKFLOW_RUN_ID}"
echo "- Commit: ${HEAD_SHA}"
echo
echo "This issue is labeled for autofix so the existing agent can create a repair PR."
} > "${body_file}"

issue_url="$(
gh issue create \
--repo "${REPO}" \
--title "Main CI failed: ${WORKFLOW_NAME} on ${short_sha}" \
--body-file "${body_file}"
)"

apply_autofix_route "${issue_url}"
31 changes: 29 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,28 @@ jobs:
run: |-
npm run verify:installation-release -- --dir dist/standalone

- name: 'Generate AI-assisted stable release notes'
if: |-
${{ needs.prepare.outputs.is_dry_run == 'false' && needs.prepare.outputs.is_nightly == 'false' && needs.prepare.outputs.is_preview == 'false' }}
continue-on-error: true
Comment thread
yiliang114 marked this conversation as resolved.
timeout-minutes: 5
env:
GITHUB_TOKEN: '${{ secrets.CI_BOT_PAT }}'
OPENAI_API_KEY: '${{ secrets.OPENAI_API_KEY }}'
OPENAI_BASE_URL: '${{ secrets.OPENAI_BASE_URL }}'
OPENAI_MODEL: '${{ secrets.OPENAI_MODEL }}'
RELEASE_BRANCH: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
RELEASE_NOTES_FILE: '${{ runner.temp }}/release-notes.md'
RELEASE_TAG: '${{ needs.prepare.outputs.release_tag }}'
PREVIOUS_RELEASE_TAG: '${{ needs.prepare.outputs.previous_release_tag }}'
run: |-
node scripts/generate-release-notes.js \
--repo="${GITHUB_REPOSITORY}" \
--tag="${RELEASE_TAG}" \
--previous-tag="${PREVIOUS_RELEASE_TAG}" \
--target="${RELEASE_BRANCH}" \
--output="${RELEASE_NOTES_FILE}"

- name: 'Create GitHub Release and Tag'
if: |-
${{ needs.prepare.outputs.is_dry_run == 'false' }}
Expand All @@ -471,20 +493,25 @@ jobs:
PREVIOUS_RELEASE_TAG: '${{ needs.prepare.outputs.previous_release_tag }}'
IS_NIGHTLY: '${{ needs.prepare.outputs.is_nightly }}'
IS_PREVIEW: '${{ needs.prepare.outputs.is_preview }}'
RELEASE_NOTES_FILE: '${{ runner.temp }}/release-notes.md'
run: |-
PRERELEASE_FLAG=""
if [[ "${IS_NIGHTLY}" == "true" || "${IS_PREVIEW}" == "true" ]]; then
PRERELEASE_FLAG="--prerelease"
fi

NOTES_ARGS=(--notes-start-tag "${PREVIOUS_RELEASE_TAG}" --generate-notes)
if [[ "${IS_NIGHTLY}" == "false" && "${IS_PREVIEW}" == "false" && -s "${RELEASE_NOTES_FILE}" ]]; then
NOTES_ARGS=(--notes-file "${RELEASE_NOTES_FILE}")
fi

gh release create "${RELEASE_TAG}" \
dist/cli.js \
dist/standalone/qwen-code-* \
dist/standalone/SHA256SUMS \
--target "${RELEASE_BRANCH}" \
--title "Release ${RELEASE_TAG}" \
--notes-start-tag "${PREVIOUS_RELEASE_TAG}" \
--generate-notes \
"${NOTES_ARGS[@]}" \
${PRERELEASE_FLAG}

- name: 'Regenerate CHANGELOG.md'
Expand Down
20 changes: 17 additions & 3 deletions scripts/generate-changelog.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,19 @@ const SECTION_ORDER = SECTIONS.map((section) => section.name);

/** Matches a stable `vX.Y.Z` tag (no `-preview` / `-nightly` suffix). */
const STABLE_TAG_RE = /^v?(\d+)\.(\d+)\.(\d+)$/;
const CURATED_RELEASE_MARKER = '<!-- qwen-release-notes:v1 -->';

/**
* Matches a GitHub "What's Changed" bullet, e.g.
* * fix(core): do a thing by @octocat in https://github.com/o/r/pull/42
* The title is captured greedily so a trailing " by @user in <pr-url>" binds to
* the last occurrence, and "New Contributors" / "Full Changelog" lines (which
* lack the " by @… in …/pull/N" tail) are skipped. The author group allows a
* trailing `[bot]` so GitHub App authors (e.g. `@dependabot[bot]`) still match.
* lack the " by @… in …/pull/N" tail) are skipped. Author groups allow a
* trailing `[bot]` and optional `with @collaborator` credits generated by
* GitHub.
*/
const ENTRY_RE =
/^[*-]\s+(.+)\s+by\s+@([A-Za-z0-9-]+(?:\[bot\])?)\s+in\s+(https?:\/\/\S+\/pull\/(\d+))\s*$/;
/^[*-]\s+(.+)\s+by\s+@([A-Za-z0-9-]+(?:\[bot\])?)(?:\s+with\s+@[A-Za-z0-9-]+(?:\[bot\])?)*\s+in\s+(https?:\/\/\S+\/pull\/(\d+))\s*$/;

/**
* Splits a conventional-commit subject into
Expand Down Expand Up @@ -149,6 +151,17 @@ export function formatRelease(release) {
: `## [${release.version}] - ${release.date}`;
lines.push(heading, '');

if (release.body?.trimStart().startsWith(CURATED_RELEASE_MARKER)) {
const curated = release.body
.split(/\r?\n/)
.filter((line) => line.trim() !== CURATED_RELEASE_MARKER)
.map((line) => line.replace(/^(#{2,5})(\s+)/, '#$1$2'))
.join('\n')
.trim();
lines.push(curated, '');
return lines.join('\n');
}

const buckets = new Map();
for (const entry of release.entries) {
const cat = categorize(entry.title);
Expand Down Expand Up @@ -213,6 +226,7 @@ export function toReleaseModel(raw) {
version: match ? `${match[1]}.${match[2]}.${match[3]}` : null,
date: (raw.date || '').slice(0, 10),
htmlUrl: raw.url || '',
body: raw.body || '',
Comment thread
yiliang114 marked this conversation as resolved.
entries: parseReleaseEntries(raw.body),
};
}
Expand Down
Loading
Loading