diff --git a/.github/workflows/qwen-autofix.yml b/.github/workflows/qwen-autofix.yml index 8d1dda1c8f..7f7377cce4 100644 --- a/.github/workflows/qwen-autofix.yml +++ b/.github/workflows/qwen-autofix.yml @@ -517,6 +517,27 @@ jobs: done fi + - name: 'Select issue sandbox image' + id: 'issue_sandbox_image' + if: |- + ${{ steps.decision.outputs.go_issue != '' }} + run: |- + qwen_version="$(npm view @qwen-code/qwen-code@latest version)" + version_image="ghcr.io/qwenlm/qwen-code:${qwen_version}" + fallback_image="ghcr.io/qwenlm/qwen-code:latest" + sandbox_image="${version_image}" + if docker manifest inspect "${version_image}" > /dev/null 2>&1; then + echo "Using sandbox image ${sandbox_image}" + elif docker manifest inspect "${fallback_image}" > /dev/null 2>&1; then + sandbox_image="${fallback_image}" + echo "::warning::Sandbox image ${version_image} is not available; falling back to ${fallback_image}." + else + echo "::error::Neither sandbox image ${version_image} nor ${fallback_image} is available." + exit 1 + fi + echo "QWEN_SANDBOX_IMAGE=${sandbox_image}" >> "${GITHUB_ENV}" + echo "qwen_version=${qwen_version}" >> "${GITHUB_OUTPUT}" + - name: 'Claim issue' id: 'claim' if: |- @@ -552,6 +573,7 @@ jobs: OPENAI_API_KEY: '${{ secrets.OPENAI_API_KEY }}' OPENAI_BASE_URL: '${{ secrets.OPENAI_BASE_URL }}' OPENAI_MODEL: '${{ vars.QWEN_PR_REVIEW_MODEL }}' + version: '${{ steps.issue_sandbox_image.outputs.qwen_version }}' settings_json: |- { "maxSessionTurns": 400, @@ -1011,6 +1033,25 @@ jobs: echo '--- feedback.md ---' cat "${WORKDIR}/feedback.md" + - name: 'Select review sandbox image' + id: 'review_sandbox_image' + run: |- + qwen_version="$(npm view @qwen-code/qwen-code@latest version)" + version_image="ghcr.io/qwenlm/qwen-code:${qwen_version}" + fallback_image="ghcr.io/qwenlm/qwen-code:latest" + sandbox_image="${version_image}" + if docker manifest inspect "${version_image}" > /dev/null 2>&1; then + echo "Using sandbox image ${sandbox_image}" + elif docker manifest inspect "${fallback_image}" > /dev/null 2>&1; then + sandbox_image="${fallback_image}" + echo "::warning::Sandbox image ${version_image} is not available; falling back to ${fallback_image}." + else + echo "::error::Neither sandbox image ${version_image} nor ${fallback_image} is available." + exit 1 + fi + echo "QWEN_SANDBOX_IMAGE=${sandbox_image}" >> "${GITHUB_ENV}" + echo "qwen_version=${qwen_version}" >> "${GITHUB_OUTPUT}" + - name: 'Triage and address' id: 'address' uses: 'QwenLM/qwen-code-action@5fd6818d04d64e87d255ee4d5f77995e32fbf4c2' @@ -1021,6 +1062,7 @@ jobs: OPENAI_API_KEY: '${{ secrets.OPENAI_API_KEY }}' OPENAI_BASE_URL: '${{ secrets.OPENAI_BASE_URL }}' OPENAI_MODEL: '${{ vars.QWEN_PR_REVIEW_MODEL }}' + version: '${{ steps.review_sandbox_image.outputs.qwen_version }}' settings_json: |- { "maxSessionTurns": 400, diff --git a/scripts/tests/qwen-autofix-workflow.test.js b/scripts/tests/qwen-autofix-workflow.test.js index 4f46ac8978..b1be2a8652 100644 --- a/scripts/tests/qwen-autofix-workflow.test.js +++ b/scripts/tests/qwen-autofix-workflow.test.js @@ -16,6 +16,14 @@ const filterUnattendedCandidates = workflow.match( /filter_unattended_candidates\(\) \{[\s\S]*?\n[ ]{12}\}/, )?.[0] ?? ''; +const issueSandboxImageStep = + workflow.match( + /- name: 'Select issue sandbox image'[\s\S]*?(?=\n {6}- name: 'Claim issue')/, + )?.[0] ?? ''; +const reviewSandboxImageStep = + workflow.match( + /- name: 'Select review sandbox image'[\s\S]*?(?=\n {6}- name: 'Triage and address')/, + )?.[0] ?? ''; describe('qwen-autofix workflow', () => { it('does not classify tier-2 issues with incomplete fallback comments', () => { @@ -138,4 +146,31 @@ describe('qwen-autofix workflow', () => { '.author.login] | map(select', ); }); + + it('falls back to the floating sandbox image only when the matching version image is missing', () => { + expect(issueSandboxImageStep.length).toBeGreaterThan(0); + expect(reviewSandboxImageStep.length).toBeGreaterThan(0); + for (const step of [issueSandboxImageStep, reviewSandboxImageStep]) { + expect(step).toContain('npm view @qwen-code/qwen-code@latest version'); + expect(step).toContain( + 'version_image="ghcr.io/qwenlm/qwen-code:${qwen_version}"', + ); + expect(step).toContain('fallback_image="ghcr.io/qwenlm/qwen-code:latest"'); + expect(step).toContain('docker manifest inspect "${version_image}"'); + expect(step).toContain('docker manifest inspect "${fallback_image}"'); + expect(step).toContain('QWEN_SANDBOX_IMAGE=${sandbox_image}'); + expect(step).toContain( + 'echo "qwen_version=${qwen_version}" >> "${GITHUB_OUTPUT}"', + ); + expect(step).toContain( + '::warning::Sandbox image ${version_image} is not available; falling back to ${fallback_image}.', + ); + } + expect(workflow).toContain( + "version: '${{ steps.issue_sandbox_image.outputs.qwen_version }}'", + ); + expect(workflow).toContain( + "version: '${{ steps.review_sandbox_image.outputs.qwen_version }}'", + ); + }); });