Remove SqlServer module version pin to fix Azure SQL provisioning failures #172
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Create Failing-Test Issue | |
| on: | |
| issue_comment: | |
| types: [created] | |
| workflow_dispatch: | |
| inputs: | |
| test_query: | |
| description: 'Test name to create an issue for (leave empty to list all failures)' | |
| required: false | |
| type: string | |
| source_url: | |
| description: 'Source URL: PR, workflow run, or workflow job URL' | |
| required: true | |
| type: string | |
| workflow: | |
| description: 'Workflow selector alias or file path' | |
| required: false | |
| default: 'ci' | |
| type: string | |
| force_new: | |
| description: 'Create a new issue even if one already exists' | |
| required: false | |
| default: false | |
| type: boolean | |
| pr_number: | |
| description: 'PR or issue number to post result comments on (optional)' | |
| required: false | |
| type: number | |
| permissions: {} | |
| concurrency: | |
| group: >- | |
| create-failing-test-issue-${{ | |
| github.event_name == 'workflow_dispatch' | |
| && format('dispatch-{0}', github.run_id) | |
| || format('{0}-{1}', | |
| github.event.issue.pull_request && 'pr' || 'issue', | |
| github.event.issue.number) | |
| }} | |
| cancel-in-progress: false | |
| jobs: | |
| create_failing_test_issue: | |
| name: Create failing-test issue | |
| if: >- | |
| github.repository == 'microsoft/aspire' && | |
| (github.event_name == 'workflow_dispatch' || | |
| startsWith(github.event.comment.body, '/create-issue')) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| permissions: | |
| contents: read # checkout repository | |
| issues: write # create/reopen/comment on issues | |
| pull-requests: write # comment on PRs | |
| actions: read # list workflow runs and download artifacts | |
| steps: | |
| - name: Verify user has write access | |
| if: github.event_name == 'issue_comment' | |
| id: verify-permission | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 | |
| with: | |
| script: | | |
| const commentUser = context.payload.comment.user.login; | |
| const { data: permission } = await github.rest.repos.getCollaboratorPermissionLevel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| username: commentUser | |
| }); | |
| const writePermissions = ['admin', 'maintain', 'write']; | |
| if (!writePermissions.includes(permission.permission)) { | |
| const message = `@${commentUser} The \`/create-issue\` command requires write, maintain, or admin access to this repository.`; | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: message | |
| }); | |
| core.setOutput('error_message', message); | |
| core.setFailed(message); | |
| return; | |
| } | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| if: success() | |
| with: | |
| persist-credentials: false | |
| - name: Extract command | |
| if: success() | |
| id: extract-command | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 | |
| with: | |
| script: | | |
| if (context.eventName === 'workflow_dispatch') { | |
| const testQuery = context.payload.inputs?.test_query ?? ''; | |
| const sourceUrl = context.payload.inputs?.source_url ?? ''; | |
| const workflow = context.payload.inputs?.workflow ?? 'ci'; | |
| const forceNew = context.payload.inputs?.force_new === 'true'; | |
| const listOnly = !testQuery; | |
| core.setOutput('test_query', testQuery); | |
| core.setOutput('source_url', sourceUrl); | |
| core.setOutput('workflow', workflow); | |
| core.setOutput('force_new', forceNew ? 'true' : 'false'); | |
| core.setOutput('list_only', listOnly ? 'true' : 'false'); | |
| core.setOutput('pr_number', context.payload.inputs?.pr_number ?? ''); | |
| return; | |
| } | |
| const helper = require(`${process.env.GITHUB_WORKSPACE}/.github/workflows/create-failing-test-issue.js`); | |
| const defaultSourceUrl = context.payload.issue.pull_request | |
| ? `https://github.com/${context.repo.owner}/${context.repo.repo}/pull/${context.issue.number}` | |
| : null; | |
| const parsed = helper.parseCommand(context.payload.comment.body, defaultSourceUrl); | |
| if (!parsed.success) { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: `@${context.payload.comment.user.login} ❌ ${parsed.errorMessage}` | |
| }); | |
| core.setOutput('error_message', parsed.errorMessage); | |
| core.setFailed(parsed.errorMessage); | |
| return; | |
| } | |
| core.setOutput('test_query', parsed.testQuery); | |
| core.setOutput('source_url', parsed.sourceUrl ?? ''); | |
| core.setOutput('workflow', parsed.workflow); | |
| core.setOutput('force_new', parsed.forceNew ? 'true' : 'false'); | |
| core.setOutput('list_only', parsed.listOnly ? 'true' : 'false'); | |
| core.setOutput('pr_number', String(context.issue.number)); | |
| - name: Add processing reaction | |
| if: success() && github.event_name == 'issue_comment' | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 | |
| with: | |
| script: | | |
| await github.rest.reactions.createForIssueComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: context.payload.comment.id, | |
| content: 'eyes' | |
| }); | |
| - name: Setup .NET SDK | |
| if: success() | |
| uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 | |
| with: | |
| global-json-file: global.json | |
| - name: Resolve failing test details | |
| if: success() | |
| id: resolve-failure | |
| continue-on-error: true | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TEST_QUERY: ${{ steps.extract-command.outputs.test_query }} | |
| SOURCE_URL: ${{ steps.extract-command.outputs.source_url }} | |
| WORKFLOW_SELECTOR: ${{ steps.extract-command.outputs.workflow }} | |
| FORCE_NEW: ${{ steps.extract-command.outputs.force_new }} | |
| LIST_ONLY: ${{ steps.extract-command.outputs.list_only }} | |
| run: | | |
| args=(--workflow "$WORKFLOW_SELECTOR" --repo "${GITHUB_REPOSITORY}") | |
| if [ "$LIST_ONLY" != "true" ]; then | |
| args+=(--test "$TEST_QUERY") | |
| fi | |
| if [ -n "$SOURCE_URL" ]; then | |
| args+=(--url "$SOURCE_URL") | |
| fi | |
| if [ "$FORCE_NEW" = "true" ]; then | |
| args+=(--force-new) | |
| fi | |
| dotnet build tools/CreateFailingTestIssue -v:q | |
| dotnet run --no-build --project tools/CreateFailingTestIssue -- "${args[@]}" --output "$RUNNER_TEMP/failing-test-result.json" | |
| - name: Create or update failing-test issue | |
| if: steps.resolve-failure.outcome != 'skipped' | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 | |
| env: | |
| RESULT_PATH: ${{ runner.temp }}/failing-test-result.json | |
| FORCE_NEW: ${{ steps.extract-command.outputs.force_new }} | |
| LIST_ONLY: ${{ steps.extract-command.outputs.list_only }} | |
| PR_NUMBER: ${{ steps.extract-command.outputs.pr_number }} | |
| RESOLVE_OUTCOME: ${{ steps.resolve-failure.outcome }} | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const helper = require(`${process.env.GITHUB_WORKSPACE}/.github/workflows/create-failing-test-issue.js`); | |
| const prNumber = process.env.PR_NUMBER ? parseInt(process.env.PR_NUMBER, 10) : null; | |
| const resolverFailed = process.env.RESOLVE_OUTCOME === 'failure'; | |
| const hasResultFile = fs.existsSync(process.env.RESULT_PATH) && fs.statSync(process.env.RESULT_PATH).size > 0; | |
| async function postComment(body) { | |
| if (!prNumber) { | |
| core.info(`No PR/issue number available. Comment:\n${body}`); | |
| return; | |
| } | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| body | |
| }); | |
| } | |
| const helpBlock = [ | |
| '📋 **`/create-issue` — Usage**', | |
| '', | |
| 'Creates or updates a failing-test issue from CI failures.', | |
| '', | |
| '```', | |
| '/create-issue <test-name>', | |
| '/create-issue <test-name> <pr|run|job-url>', | |
| '/create-issue --test "<test-name>"', | |
| '/create-issue --test "<test-name>" --url <pr|run|job-url>', | |
| '/create-issue --test "<test-name>" --force-new', | |
| '```', | |
| ].join('\n'); | |
| // If the resolver step failed and produced no output, report the error | |
| if (resolverFailed && !hasResultFile) { | |
| const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; | |
| const message = `❌ The failing-test resolver failed to run. See the [workflow run](${runUrl}) for details.`; | |
| await postComment(message); | |
| core.setFailed(message); | |
| return; | |
| } | |
| // List-only mode: show available failures + help when no --test was given | |
| if (process.env.LIST_ONLY === 'true') { | |
| const resultJson = hasResultFile | |
| ? JSON.parse(fs.readFileSync(process.env.RESULT_PATH, 'utf8')) | |
| : null; | |
| const listResult = helper.formatListResponse(process.env.RESOLVE_OUTCOME, resultJson); | |
| if (listResult.error) { | |
| const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; | |
| const message = `❌ ${listResult.message} See the [workflow run](${runUrl}) for details.`; | |
| await postComment(message); | |
| core.setFailed(message); | |
| return; | |
| } | |
| await postComment(`${listResult.message}${helpBlock}`); | |
| return; | |
| } | |
| if (!hasResultFile) { | |
| const message = '❌ The failing-test resolver did not produce a JSON result. See the workflow run for details.'; | |
| await postComment(message); | |
| core.setFailed(message); | |
| return; | |
| } | |
| const result = JSON.parse(fs.readFileSync(process.env.RESULT_PATH, 'utf8')); | |
| if (!result.success) { | |
| const candidates = result.diagnostics?.availableFailedTests?.length | |
| ? `\n\n**Available failed tests:**\n${result.diagnostics.availableFailedTests.map(name => `- \`${name}\``).join('\n')}` | |
| : ''; | |
| const message = `❌ ${result.errorMessage ?? 'The failing-test resolver could not create an issue.'}${candidates}`; | |
| await postComment(message); | |
| core.setFailed(result.errorMessage ?? 'The failing-test resolver failed.'); | |
| return; | |
| } | |
| let targetIssue = null; | |
| if (process.env.FORCE_NEW !== 'true') { | |
| const query = helper.buildIssueSearchQuery(context.repo.owner, context.repo.repo, result.issue.metadataMarker); | |
| const { data: search } = await github.rest.search.issuesAndPullRequests({ | |
| q: query, | |
| per_page: 20 | |
| }); | |
| const issues = search.items.filter(item => !item.pull_request); | |
| targetIssue = issues.find(item => item.state === 'open') ?? issues.find(item => item.state === 'closed') ?? null; | |
| } | |
| let action; | |
| let issueNumber; | |
| let issueUrl; | |
| if (targetIssue && targetIssue.state === 'open') { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: targetIssue.number, | |
| body: result.issue.commentBody | |
| }); | |
| action = 'updated'; | |
| issueNumber = targetIssue.number; | |
| issueUrl = targetIssue.html_url; | |
| } else if (targetIssue && targetIssue.state === 'closed') { | |
| await github.rest.issues.update({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: targetIssue.number, | |
| state: 'open' | |
| }); | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: targetIssue.number, | |
| body: result.issue.commentBody | |
| }); | |
| action = 'reopened'; | |
| issueNumber = targetIssue.number; | |
| issueUrl = targetIssue.html_url; | |
| } else { | |
| const { data: issue } = await github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title: result.issue.title, | |
| body: result.issue.body, | |
| labels: result.issue.labels | |
| }); | |
| action = 'created'; | |
| issueNumber = issue.number; | |
| issueUrl = issue.html_url; | |
| } | |
| const testName = result.match?.canonicalTestName ?? result.match?.displayTestName ?? ''; | |
| let disableHint = ''; | |
| if (testName) { | |
| disableHint = `\n\nTo disable this test on your PR, comment:\n\`\`\`\n/disable-test ${testName} ${issueUrl}\n\`\`\``; | |
| } | |
| await postComment(`✅ ${action[0].toUpperCase()}${action.slice(1)} failing-test issue #${issueNumber}: ${issueUrl}${disableHint}`); | |
| if (context.eventName === 'issue_comment') { | |
| await github.rest.reactions.createForIssueComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: context.payload.comment.id, | |
| content: 'rocket' | |
| }); | |
| } | |
| - name: Post failure comment on unexpected error | |
| if: failure() && steps.extract-command.outcome == 'success' && (steps.verify-permission.outcome == 'success' || steps.verify-permission.outcome == 'skipped') | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 | |
| env: | |
| PR_NUMBER: ${{ steps.extract-command.outputs.pr_number }} | |
| with: | |
| script: | | |
| const prNumber = process.env.PR_NUMBER ? parseInt(process.env.PR_NUMBER, 10) : null; | |
| const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; | |
| const message = `❌ The \`/create-issue\` command failed. See the [workflow run](${runUrl}) for details.`; | |
| if (prNumber) { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| body: message | |
| }); | |
| } else { | |
| core.info(message); | |
| } |