openai/openai-dotnet
Publicmirrored from https://github.com/openai/openai-dotnetAvailable
.github/workflows/record-test.yml
152lines · modecode
| 1 | # This workflow is triggered manually for a target branch and requires an NUnit.Where expression to run a |
| 2 | # subset of tests in Record mode. It commits the resulting session recordings and creates a PR |
| 3 | # against the target branch. Use this workflow to record new tests or re-record existing tests on |
| 4 | # behalf of the Copilot Coding Agent. |
| 5 | # |
| 6 | # For more information, about expressions using NUnit's Test Selection Language, see: |
| 7 | # https://docs.nunit.org/articles/nunit/running-tests/Test-Selection-Language.html |
| 8 | # |
| 9 | # Example: |
| 10 | # test =~ ".*ChatTests.*" or test == "OpenAI.Tests.Embeddings.EmbeddingsTests(True).GenerateSingleEmbedding" |
| 11 | name: "[Test] Record tests" |
| 12 | |
| 13 | on: |
| 14 | workflow_dispatch: |
| 15 | inputs: |
| 16 | nunit_where: |
| 17 | description: 'NUnit.Where expression' |
| 18 | required: true |
| 19 | type: string |
| 20 | |
| 21 | permissions: |
| 22 | contents: write |
| 23 | pull-requests: write |
| 24 | |
| 25 | # Runs targeting the same branch are queued to prevent conflicting recording branches. |
| 26 | # Runs targeting different branches are allowed in parallel. |
| 27 | concurrency: |
| 28 | group: record-test-${{ github.ref }} |
| 29 | cancel-in-progress: false |
| 30 | |
| 31 | jobs: |
| 32 | record: |
| 33 | name: Record tests |
| 34 | runs-on: ubuntu-latest |
| 35 | environment: Live Testing |
| 36 | env: |
| 37 | LATEST_TEST_TFM: net10.0 |
| 38 | TEST_NUNIT_WHERE: ${{ inputs.nunit_where }} |
| 39 | VERSION_SUFFIX_ARGS: ${{ format('/p:VersionSuffix="alpha.{0}"', github.run_number) }} |
| 40 | steps: |
| 41 | - name: Checkout code |
| 42 | uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 |
| 43 | |
| 44 | - name: Setup .NET 10 |
| 45 | uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 |
| 46 | with: |
| 47 | dotnet-version: '10.x' |
| 48 | |
| 49 | - name: Setup .NET 9 |
| 50 | uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 |
| 51 | with: |
| 52 | dotnet-version: '9.x' |
| 53 | |
| 54 | - name: Setup .NET 8 |
| 55 | uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 |
| 56 | with: |
| 57 | dotnet-version: '8.x' |
| 58 | |
| 59 | - name: Restore tools |
| 60 | run: dotnet tool restore --add-source https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-net/nuget/v3/index.json |
| 61 | |
| 62 | - name: Run tests in Record mode |
| 63 | run: dotnet test ./tests/OpenAI.Tests.csproj |
| 64 | --configuration Release |
| 65 | --framework "$LATEST_TEST_TFM" |
| 66 | --logger "trx;LogFilePrefix=record" |
| 67 | --results-directory ${{ github.workspace }}/artifacts/test-results |
| 68 | ${{ env.VERSION_SUFFIX_ARGS }} |
| 69 | -- NUnit.Where="$TEST_NUNIT_WHERE" |
| 70 | env: |
| 71 | OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} |
| 72 | CLIENTMODEL_TEST_MODE: Record |
| 73 | |
| 74 | - name: Check for recording changes |
| 75 | id: changes |
| 76 | run: | |
| 77 | STATUS_OUTPUT="$(git status --porcelain tests/SessionRecords/)" |
| 78 | if [ -z "$STATUS_OUTPUT" ]; then |
| 79 | echo "has_changes=false" >> $GITHUB_OUTPUT |
| 80 | echo "### No recording changes detected" >> $GITHUB_STEP_SUMMARY |
| 81 | else |
| 82 | echo "has_changes=true" >> $GITHUB_OUTPUT |
| 83 | echo "### Recording changes detected:" >> $GITHUB_STEP_SUMMARY |
| 84 | echo '```' >> $GITHUB_STEP_SUMMARY |
| 85 | echo "$STATUS_OUTPUT" >> $GITHUB_STEP_SUMMARY |
| 86 | echo '```' >> $GITHUB_STEP_SUMMARY |
| 87 | fi |
| 88 | |
| 89 | - name: Scan recordings for unsanitized secrets |
| 90 | if: steps.changes.outputs.has_changes == 'true' |
| 91 | run: | |
| 92 | CHANGED_FILES="$(git status --porcelain tests/SessionRecords/ | awk '{print $NF}')" |
| 93 | if echo "$CHANGED_FILES" | xargs grep -qE '(sk-|ek-)[A-Za-z0-9]'; then |
| 94 | echo "::error::Potential unsanitized secret key detected in session recordings. Please inspect and sanitize before committing." |
| 95 | exit 1 |
| 96 | else |
| 97 | echo "### No unsanitized secrets detected in recordings" >> $GITHUB_STEP_SUMMARY |
| 98 | fi |
| 99 | |
| 100 | # Playback deliberately omits --framework to validate recordings across all TFMs. |
| 101 | - name: Validate recordings in Playback mode |
| 102 | if: steps.changes.outputs.has_changes == 'true' |
| 103 | run: dotnet test ./tests/OpenAI.Tests.csproj |
| 104 | --configuration Release |
| 105 | --logger "trx;LogFilePrefix=playback" |
| 106 | --results-directory ${{ github.workspace }}/artifacts/test-results |
| 107 | ${{ env.VERSION_SUFFIX_ARGS }} |
| 108 | -- NUnit.Where="$TEST_NUNIT_WHERE" |
| 109 | env: |
| 110 | CLIENTMODEL_TEST_MODE: Playback |
| 111 | CLIENTMODEL_DISABLE_AUTO_RECORDING: "true" |
| 112 | |
| 113 | - name: Create PR with recordings |
| 114 | if: steps.changes.outputs.has_changes == 'true' |
| 115 | env: |
| 116 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 117 | run: | |
| 118 | BASE_BRANCH="${{ github.ref_name }}" |
| 119 | RECORDING_BRANCH="recordings/${{ github.run_id }}-${{ github.run_attempt }}" |
| 120 | |
| 121 | git config --local user.email "github-actions[bot]@users.noreply.github.com" |
| 122 | git config --local user.name "github-actions[bot]" |
| 123 | git checkout -b "$RECORDING_BRANCH" |
| 124 | git add tests/SessionRecords/ |
| 125 | git commit -m "Record tests for $BASE_BRANCH" |
| 126 | git push origin "$RECORDING_BRANCH" |
| 127 | |
| 128 | BODY_FILE=$(mktemp) |
| 129 | trap 'rm -f "$BODY_FILE"' EXIT |
| 130 | |
| 131 | printf 'This PR contains session recordings generated by the record-test workflow.\n\n**NUnit.Where:** `%s`\n**Workflow run:** %s' \ |
| 132 | "$TEST_NUNIT_WHERE" \ |
| 133 | "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ |
| 134 | > "$BODY_FILE" |
| 135 | |
| 136 | PR_URL=$(gh pr create \ |
| 137 | --base "$BASE_BRANCH" \ |
| 138 | --head "$RECORDING_BRANCH" \ |
| 139 | --title "Record tests for $BASE_BRANCH" \ |
| 140 | --draft \ |
| 141 | --body-file "$BODY_FILE" \ |
| 142 | --assignee "${{ github.actor }}") |
| 143 | |
| 144 | echo "### Pull request created:" >> $GITHUB_STEP_SUMMARY |
| 145 | echo "$PR_URL" >> $GITHUB_STEP_SUMMARY |
| 146 | |
| 147 | - name: Upload artifact |
| 148 | uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 |
| 149 | if: ${{ !cancelled() }} |
| 150 | with: |
| 151 | name: test-artifacts-${{ github.run_attempt }} |
| 152 | path: ${{ github.workspace }}/artifacts |
| 153 | |