diff --git a/.github/agents/agentic-workflows.agent.md b/.github/agents/agentic-workflows.agent.md index cd376c5b1b30..f7e5eb4f1cd1 100644 --- a/.github/agents/agentic-workflows.agent.md +++ b/.github/agents/agentic-workflows.agent.md @@ -19,7 +19,13 @@ This is a **dispatcher agent** that routes your request to the appropriate speci - **Creating shared components**: Routes to `create-shared-agentic-workflow` prompt - **Fixing Dependabot PRs**: Routes to `dependabot` prompt — use this when Dependabot opens PRs that modify generated manifest files (`.github/workflows/package.json`, `.github/workflows/requirements.txt`, `.github/workflows/go.mod`). Never merge those PRs directly; instead update the source `.md` files and rerun `gh aw compile --dependabot` to bundle all fixes - **Analyzing test coverage**: Routes to `test-coverage` prompt — consult this whenever the workflow reads, analyzes, or reports on test coverage data from PRs or CI runs +- **Rendering ASCII charts in markdown**: Routes to `asciicharts` guide — consult this whenever the workflow needs compact charts that render reliably in GitHub issues, comments, or discussions - **CLI commands and triggering workflows**: Routes to `cli-commands` guide — consult this whenever the user asks how to run, compile, debug, or manage workflows from the command line, or when they need the MCP tool equivalent of a `gh aw` command +- **Reducing token consumption / cost optimization**: Routes to `token-optimization` guide — consult this whenever the user asks how to reduce token usage, lower costs, speed up workflows, or measure the impact of prompt changes with experiments +- **Choosing workflow architectures and design patterns**: Routes to `patterns` guide — consult this whenever the user asks for strategy, architecture, operating models, or pattern selection for agentic workflows + +> [!IMPORTANT] +> For architecture/pattern-selection requests, load `https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/patterns.md` first. Workflows may optionally include: @@ -31,7 +37,7 @@ Workflows may optionally include: - Workflow files: `.github/workflows/*.md` and `.github/workflows/**/*.md` - Workflow lock files: `.github/workflows/*.lock.yml` - Shared components: `.github/workflows/shared/*.md` -- Configuration: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/github-agentic-workflows.md +- Configuration: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/github-agentic-workflows.md ## Problems This Solves @@ -53,7 +59,7 @@ When you interact with this agent, it will: ### Create New Workflow **Load when**: User wants to create a new workflow from scratch, add automation, or design a workflow that doesn't exist yet -**Prompt file**: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/create-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/create-agentic-workflow.md **Use cases**: - "Create a workflow that triages issues" @@ -63,7 +69,7 @@ When you interact with this agent, it will: ### Update Existing Workflow **Load when**: User wants to modify, improve, or refactor an existing workflow -**Prompt file**: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/update-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/update-agentic-workflow.md **Use cases**: - "Add web-fetch tool to the issue-classifier workflow" @@ -73,7 +79,7 @@ When you interact with this agent, it will: ### Debug Workflow **Load when**: User needs to investigate, audit, debug, or understand a workflow, troubleshoot issues, analyze logs, or fix errors -**Prompt file**: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/debug-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/debug-agentic-workflow.md **Use cases**: - "Why is this workflow failing?" @@ -83,7 +89,7 @@ When you interact with this agent, it will: ### Upgrade Agentic Workflows **Load when**: User wants to upgrade workflows to a new gh-aw version or fix deprecations -**Prompt file**: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/upgrade-agentic-workflows.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/upgrade-agentic-workflows.md **Use cases**: - "Upgrade all workflows to the latest version" @@ -93,7 +99,7 @@ When you interact with this agent, it will: ### Create a Report-Generating Workflow **Load when**: The workflow being created or updated produces reports — recurring status updates, audit summaries, analyses, or any structured output posted as a GitHub issue, discussion, or comment -**Prompt file**: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/report.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/report.md **Use cases**: - "Create a weekly CI health report" @@ -103,7 +109,7 @@ When you interact with this agent, it will: ### Create Shared Agentic Workflow **Load when**: User wants to create a reusable workflow component or wrap an MCP server -**Prompt file**: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/create-shared-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/create-shared-agentic-workflow.md **Use cases**: - "Create a shared component for Notion integration" @@ -113,7 +119,7 @@ When you interact with this agent, it will: ### Fix Dependabot PRs **Load when**: User needs to close or fix open Dependabot PRs that update dependencies in generated manifest files (`.github/workflows/package.json`, `.github/workflows/requirements.txt`, `.github/workflows/go.mod`) -**Prompt file**: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/dependabot.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/dependabot.md **Use cases**: - "Fix the open Dependabot PRs for npm dependencies" @@ -123,17 +129,27 @@ When you interact with this agent, it will: ### Analyze Test Coverage **Load when**: The workflow reads, analyzes, or reports test coverage — whether triggered by a PR, a schedule, or a slash command. Always consult this prompt before designing the coverage data strategy. -**Prompt file**: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/test-coverage.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/test-coverage.md **Use cases**: - "Create a workflow that comments coverage on PRs" - "Analyze coverage trends over time" - "Add a coverage gate that blocks PRs below a threshold" +### Render ASCII Charts in Markdown +**Load when**: The workflow needs in-markdown charts (sparklines, bars, table+trend views) that must align cleanly and render reliably across GitHub surfaces, including mobile. + +**Reference file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/asciicharts.md + +**Use cases**: +- "Show a compact trend chart in an issue comment" +- "Render a dashboard table with sparkline trends" +- "Generate aligned ASCII bars for service metrics" + ### CLI Commands Reference **Load when**: The user asks how to run, compile, debug, or manage workflows from the command line; needs the MCP tool equivalent of a `gh aw` command; or is in a restricted environment (e.g., Copilot Cloud) without direct CLI access. -**Reference file**: https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/cli-commands.md +**Reference file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/cli-commands.md **Use cases**: - "How do I trigger workflow X on the main branch?" @@ -141,6 +157,30 @@ When you interact with this agent, it will: - "I'm in Copilot Cloud — how do I compile a workflow?" - "Show me all available gh aw commands" +### Token Consumption Optimization +**Load when**: The user asks how to reduce token usage, lower workflow costs, make a workflow faster or cheaper, or measure the impact of prompt or configuration changes. + +**Reference file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/token-optimization.md + +**Use cases**: +- "How do I reduce the token cost of this workflow?" +- "My workflow is too expensive — how do I optimize it?" +- "How do I compare token usage between two runs?" +- "Should I use gh-proxy or the MCP server?" +- "How do I use sub-agents to reduce costs?" +- "How do I measure the impact of a prompt change?" + +### Workflow Pattern Selection +**Load when**: The user asks for architecture, strategy, operating model selection, or pattern recommendations for building agentic workflows. + +**Reference file**: https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/patterns.md + +**Use cases**: +- "Which pattern should I use for multi-repo rollout?" +- "How should I structure this workflow architecture?" +- "What pattern fits slash-command triage?" +- "Should this be DispatchOps or DailyOps?" + ## Instructions When a user interacts with you: @@ -185,12 +225,12 @@ gh aw compile --validate ## Important Notes -- Always reference the instructions file at https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/github-agentic-workflows.md for complete documentation +- Always reference the instructions file at https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/github-agentic-workflows.md for complete documentation - Use the MCP tool `agentic-workflows` when running in GitHub Copilot Cloud - Workflows must be compiled to `.lock.yml` files before running in GitHub Actions - **Bash tools are enabled by default** - Don't restrict bash commands unnecessarily since workflows are sandboxed by the AWF - Follow security best practices: minimal permissions, explicit network access, no template injection -- **Network configuration**: Use ecosystem identifiers (`node`, `python`, `go`, etc.) or explicit FQDNs in `network.allowed`. Bare shorthands like `npm` or `pypi` are **not** valid. See https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/network.md for the full list of valid ecosystem identifiers and domain patterns. +- **Network configuration**: Use ecosystem identifiers (`node`, `python`, `go`, etc.) or explicit FQDNs in `network.allowed`. Bare shorthands like `npm` or `pypi` are **not** valid. See https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/network.md for the full list of valid ecosystem identifiers and domain patterns. - **Single-file output**: When creating a workflow, produce exactly **one** workflow `.md` file. Do not create separate documentation files (architecture docs, runbooks, usage guides, etc.). If documentation is needed, add a brief `## Usage` section inside the workflow file itself. - **Triggering runs**: Always use `gh aw run ` to trigger a workflow on demand — not `gh workflow run .lock.yml`. `gh aw run` handles workflow resolution by short name, input parsing and validation, and correct run-tracking for agentic workflows. Use `--ref ` to run on a specific branch. -- **CLI commands reference**: For a complete guide on all `gh aw` commands and their MCP tool equivalents (for restricted environments), see https://github.com/github/gh-aw/blob/v0.72.1/.github/aw/cli-commands.md +- **CLI commands reference**: For a complete guide on all `gh aw` commands and their MCP tool equivalents (for restricted environments), see https://github.com/github/gh-aw/blob/v0.74.8/.github/aw/cli-commands.md diff --git a/.github/aw/actions-lock.json b/.github/aw/actions-lock.json index 4b30f2d3389b..06276c7f1e4c 100644 --- a/.github/aw/actions-lock.json +++ b/.github/aw/actions-lock.json @@ -25,10 +25,10 @@ "version": "v7.0.1", "sha": "043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" }, - "github/gh-aw-actions/setup@v0.72.1": { + "github/gh-aw-actions/setup@v0.74.8": { "repo": "github/gh-aw-actions/setup", - "version": "v0.72.1", - "sha": "bc56a0cad2f450c562810785ef38649c04db812a" + "version": "v0.74.8", + "sha": "efa55847f72aadb03490d955263ff911bf758700" } }, "containers": { diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 11176de6fa6a..7f0e372f40bf 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -146,6 +146,10 @@ Located in `msbuild/` directory: working directory (e.g., `GetDirectoryName` with a relative path may produce unexpected results in a cross-platform build). +### FileWrites + +If a target or task creates a file, that file must be added to the `FileWrites` item group. This ensures MSBuild's incremental clean can delete generated files. Additionally, if a target produces multiple output files, all of them should be listed in the target's `Outputs` attribute for correct incremental build behavior. + ### Project Templates Common project structure for Apple platform apps: diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6cc00712d1c7..13434fb1a2d8 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,8 +1,10 @@ -version: 2 updates: - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" - cooldown: - default-days: 7 +- cooldown: + default-days: 7 + directory: / + ignore: + - dependency-name: "github/gh-aw-actions/**" # Managed by gh aw compile. Version-locked to the gh-aw compiler; do not bump. + package-ecosystem: github-actions + schedule: + interval: weekly +version: 2 diff --git a/.github/skills/update-expected-app-size/SKILL.md b/.github/skills/update-expected-app-size/SKILL.md new file mode 100644 index 000000000000..88d888c17a0e --- /dev/null +++ b/.github/skills/update-expected-app-size/SKILL.md @@ -0,0 +1,126 @@ +--- +name: update-expected-app-size +description: >- + Download updated expected app size files from Azure DevOps CI artifacts for + the current branch. Use when app size tests fail in CI and the user wants to + update the expected files locally. Trigger on "update app size", "download + expected files", "fix app size test", or "update expected app size files". +--- + +# Update Expected App Size Files + +Download updated expected app size files from Azure DevOps artifacts for the current branch's PR build, and apply them to the repository. + +## When to Use + +- App size tests failed in CI and the user wants to update the expected files +- User asks to "update app size", "download expected files", or "fix app size test failures" +- User wants to pull the updated expected files from a recent CI build + +## Background + +The app size tests (`tests/dotnet/UnitTests/AppSizeTest.cs`) compare the built app's size and preserved APIs against expected files stored in `tests/dotnet/UnitTests/expected/`. When the test detects a difference and `WRITE_KNOWN_FAILURES` is not set, it writes the updated expected file to `$(Build.ArtifactStagingDirectory)/updated-expected-sizes/`, and a pipeline step publishes this directory as a build artifact. + +The artifact name follows the pattern `updated-expected-sizes-{testPrefix}-{attempt}` (e.g., `updated-expected-sizes-dotnettests_ios-1`). Inside the artifact, files are named: +- `{Platform}-{Runtime}-size.txt` — e.g., `iOS-MonoVM-size.txt` +- `{Platform}-{Runtime}-preservedapis.txt` — e.g., `iOS-MonoVM-preservedapis.txt` + +The expected files on disk are at: +- `tests/dotnet/UnitTests/expected/{Platform}-{Runtime}-size.txt` +- `tests/dotnet/UnitTests/expected/{Platform}-{Runtime}-preservedapis.txt` + +## Workflow + +### 1. Determine the current branch and PR + +```bash +BRANCH=$(git branch --show-current) +# Find the PR number for this branch +gh pr list --head "$BRANCH" --repo dotnet/macios --json number,url --jq '.[0]' +``` + +If no PR is found, inform the user that this skill requires a PR to exist for the current branch (so that CI has run). + +### 2. Find the Azure DevOps build + +The CI builds for PRs in dotnet/macios run in the `devdiv` Azure DevOps organization, project `DevDiv`. + +Use the GitHub PR checks to find the Azure DevOps build URL: + +```bash +gh pr checks --repo dotnet/macios +``` + +Look for a check that links to Azure DevOps. The build URL will look like: +``` +https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=XXXXXXX +``` + +Extract the `buildId` from the URL. + +### 3. Download the artifacts + +Use the Azure DevOps REST API to list and download artifacts: + +```bash +# List artifacts for the build +TOKEN=$(az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798 --query accessToken -o tsv) +curl -s "https://devdiv.visualstudio.com/DevDiv/_apis/build/builds/{buildId}/artifacts?api-version=7.0" \ + -H "Authorization: Bearer $TOKEN" +``` + +Look for artifacts whose names contain `updated-expected-sizes` (e.g., `updated-expected-sizes-dotnettests_ios-1`). Get the artifact's `downloadUrl` and download it: + +```bash +# Get the download URL for a specific artifact +ARTIFACT_INFO=$(curl -s "https://devdiv.visualstudio.com/DevDiv/_apis/build/builds/{buildId}/artifacts?artifactName={artifactName}&api-version=7.0" \ + -H "Authorization: Bearer $TOKEN") +DOWNLOAD_URL=$(echo "$ARTIFACT_INFO" | python3 -c "import sys,json; print(json.load(sys.stdin)['resource']['downloadUrl'])") + +# Download the artifact zip +curl -sL "$DOWNLOAD_URL" -H "Authorization: Bearer $TOKEN" -o artifact.zip +``` + +If `az` is not available or not authenticated, direct the user to download manually from the Azure DevOps build artifacts page. + +### 4. Place the files + +Extract the downloaded artifact zip and place the files in the expected directory: + +```bash +EXPECTED_DIR="tests/dotnet/UnitTests/expected" +unzip -o artifact.zip -d /tmp/updated-sizes/ +cp /tmp/updated-sizes/*/*.txt "$EXPECTED_DIR/" +``` + +The files inside the zip already have the correct names (e.g., `iOS-MonoVM-size.txt`) and can be copied directly. + +### 5. Verify and commit + +After placing the files: +1. Run `git diff` to show what changed +2. Ask the user if the changes look correct +3. If confirmed, commit the changes: + ```bash + git add tests/dotnet/UnitTests/expected/ + git commit -m "[tests] Update expected app size files" + ``` + +## Fallback: Manual Download + +If automated download fails (auth issues, etc.), provide the user with: +1. The Azure DevOps build URL +2. Instructions to navigate to the build → Summary → Artifacts section +3. Look for individual artifacts whose names match the patterns above +4. Download each file and place it as `tests/dotnet/UnitTests/expected/{artifactName}.txt` + +## Fallback: Run Locally + +If the user can build locally, they can update the expected files directly: + +```bash +WRITE_KNOWN_FAILURES=1 tests-dotnet AppSizeTest +``` + +This runs the tests, updates the expected files in place, and marks the tests as passed. + diff --git a/.github/workflows/autoformat-v2.yml b/.github/workflows/autoformat-v2.yml new file mode 100644 index 000000000000..695354c78d1a --- /dev/null +++ b/.github/workflows/autoformat-v2.yml @@ -0,0 +1,97 @@ +name: Autoformat code v2 +on: pull_request + +permissions: {} + +jobs: + # Job for same-repo PRs: format and push directly + autoformat-push: + name: Autoformat and push + runs-on: ubuntu-latest + if: github.event.pull_request.head.repo.full_name == github.repository + permissions: + contents: write + + steps: + - name: 'Checkout' + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + ref: ${{ github.head_ref }} + fetch-depth: 1 + persist-credentials: false + + - name: 'Install .NET' + uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5 + with: + global-json-file: ./global.json + + - name: 'Autoformat' + run: ./tools/autoformat.sh + + - name: 'Check for changes' + id: check + run: | + if git diff --quiet; then + echo "changes=false" >> "$GITHUB_OUTPUT" + else + echo "changes=true" >> "$GITHUB_OUTPUT" + fi + + - name: 'Commit and push' + if: steps.check.outputs.changes == 'true' + env: + GH_TOKEN: ${{ github.token }} + run: | + git config user.email 'github-actions-autoformatter@xamarin.com' + git config user.name 'GitHub Actions Autoformatter' + git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}" + git add -A + git commit -m 'Auto-format source code' + git push + + # Job for fork PRs: format and upload patch as artifact + autoformat-artifact: + name: Autoformat and upload patch + runs-on: ubuntu-latest + if: github.event.pull_request.head.repo.full_name != github.repository + permissions: + contents: read + + steps: + - name: 'Checkout' + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.sha }} + persist-credentials: false + fetch-depth: 1 + + - name: 'Install .NET' + uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5 + with: + global-json-file: ./global.json + + - name: 'Autoformat' + run: ./tools/autoformat.sh + + - name: 'Create patch' + id: patch + run: | + if git diff --quiet; then + echo "changes=false" >> "$GITHUB_OUTPUT" + else + echo "changes=true" >> "$GITHUB_OUTPUT" + git config user.email 'github-actions-autoformatter@xamarin.com' + git config user.name 'GitHub Actions Autoformatter' + git add -A + git commit -m 'Auto-format source code' + mkdir -p autoformat-output + git format-patch HEAD~1 --stdout > autoformat-output/autoformat.patch + fi + + - name: 'Upload patch' + if: steps.patch.outputs.changes == 'true' + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: autoformat + path: autoformat-output/ diff --git a/.github/workflows/autoformat.yml b/.github/workflows/autoformat.yml deleted file mode 100644 index f20d04015aad..000000000000 --- a/.github/workflows/autoformat.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Autoformat code -on: pull_request - -# This action only need a single permission in order to autoformat the code. -permissions: - contents: read - -jobs: - autoformat-code: - name: Autoformat code - runs-on: ubuntu-latest - - steps: - - name: 'Checkout' - uses: actions/checkout@v6 - with: - fetch-depth: 0 - repository: ${{ github.event.pull_request.head.repo.full_name }} - ref: ${{ github.event.pull_request.head.sha }} - - name: 'Install .NET' - uses: actions/setup-dotnet@v5 - with: - global-json-file: ./global.json - - name: 'Autoformat' - uses: rolfbjarne/autoformat@v0.6 - with: - script: ./tools/autoformat.sh - git_user_email: 'github-actions-autoformatter@xamarin.com' - git_user_name: 'GitHub Actions Autoformatter' - checkoutSource: false diff --git a/.github/workflows/autoformat2.yml b/.github/workflows/autoformat2.yml deleted file mode 100644 index bc382aaf8c2e..000000000000 --- a/.github/workflows/autoformat2.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Autoformat code - push results -on: - workflow_run: - workflows: ["Autoformat code"] - types: - - completed - -# This action needs the following permissions in order to push the results back to the original branch. -permissions: - pull-requests: write - contents: write - -jobs: - push-and-notify: - name: Push autoformatted code and notify user - runs-on: ubuntu-latest - if: > - github.event.workflow_run.event == 'pull_request' && - github.event.workflow_run.conclusion == 'success' - steps: - - name: 'Push autoformatted patch' - uses: rolfbjarne/autoformat-push@v0.3 - with: - githubToken: ${{ secrets.GITHUB_TOKEN }} - git_user_email: 'github-actions-autoformatter@xamarin.com' - git_user_name: 'GitHub Actions Autoformatter' - commentOnPullRequest: false diff --git a/.github/workflows/ci-postmortem.lock.yml b/.github/workflows/ci-postmortem.lock.yml index 9d6b4a9a0a6e..c8d473b80999 100644 --- a/.github/workflows/ci-postmortem.lock.yml +++ b/.github/workflows/ci-postmortem.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"15354af11629eb0049ecb70f03b13ed2df90af330f1d6a40d7ce9a202538bb0b","compiler_version":"v0.71.1","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-4.5"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"239aec45b78c8799417efdd5bc6d8cc036629ec1","version":"v0.71.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.28","digest":"sha256:a8834e285807654bf680154faa710d43fe4365a0868142f5c20e48c85e137a7a","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.25.28@sha256:a8834e285807654bf680154faa710d43fe4365a0868142f5c20e48c85e137a7a"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.28","digest":"sha256:93290f2393752252911bd7c39a047f776c0b53063575e7bde4e304962a9a61cb","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.28@sha256:93290f2393752252911bd7c39a047f776c0b53063575e7bde4e304962a9a61cb"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.28","digest":"sha256:844c18280f82cd1b06345eb2f4e91966b34185bfc51c9f237c3e022e848fb474","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.25.28@sha256:844c18280f82cd1b06345eb2f4e91966b34185bfc51c9f237c3e022e848fb474"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.0","digest":"sha256:9c2228324fb1f26f39dc9471612e530ae3efc3156dac05efb2e8d212878d454d","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.0@sha256:9c2228324fb1f26f39dc9471612e530ae3efc3156dac05efb2e8d212878d454d"},{"image":"ghcr.io/github/github-mcp-server:v1.0.2","digest":"sha256:26db03408086a99cf1916348dcc4f9614206658f9082a8060dc7c81ad787f4ba","pinned_image":"ghcr.io/github/github-mcp-server:v1.0.2@sha256:26db03408086a99cf1916348dcc4f9614206658f9082a8060dc7c81ad787f4ba"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"15354af11629eb0049ecb70f03b13ed2df90af330f1d6a40d7ce9a202538bb0b","compiler_version":"v0.74.8","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-4.5"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"efa55847f72aadb03490d955263ff911bf758700","version":"v0.74.8"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.49"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.49"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.49"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.9","digest":"sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388"},{"image":"ghcr.io/github/github-mcp-server:v1.0.4"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -14,7 +14,7 @@ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ # -# This file was automatically generated by gh-aw (v0.71.1). DO NOT EDIT. +# This file was automatically generated by gh-aw (v0.74.8). DO NOT EDIT. # # To update this file, edit the corresponding .md file and run: # gh aw compile @@ -32,29 +32,29 @@ # Custom actions used: # - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 -# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 +# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 # - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 -# - github/gh-aw-actions/setup@239aec45b78c8799417efdd5bc6d8cc036629ec1 # v0.71.1 +# - github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 # # Container images used: -# - ghcr.io/github/gh-aw-firewall/agent:0.25.28@sha256:a8834e285807654bf680154faa710d43fe4365a0868142f5c20e48c85e137a7a -# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.28@sha256:93290f2393752252911bd7c39a047f776c0b53063575e7bde4e304962a9a61cb -# - ghcr.io/github/gh-aw-firewall/squid:0.25.28@sha256:844c18280f82cd1b06345eb2f4e91966b34185bfc51c9f237c3e022e848fb474 -# - ghcr.io/github/gh-aw-mcpg:v0.3.0@sha256:9c2228324fb1f26f39dc9471612e530ae3efc3156dac05efb2e8d212878d454d -# - ghcr.io/github/github-mcp-server:v1.0.2@sha256:26db03408086a99cf1916348dcc4f9614206658f9082a8060dc7c81ad787f4ba +# - ghcr.io/github/gh-aw-firewall/agent:0.25.49 +# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.49 +# - ghcr.io/github/gh-aw-firewall/squid:0.25.49 +# - ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388 +# - ghcr.io/github/github-mcp-server:v1.0.4 # - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f name: "CI Post-Mortem Analysis" -"on": +on: schedule: - - cron: "45 11 * * 0" + - cron: "11 2 * * 0" # Friendly format: weekly on sunday (scattered) workflow_dispatch: inputs: aw_context: default: "" - description: Agent caller context (used internally by Agentic Workflows). + description: "Agent caller context (used internally by Agentic Workflows)." required: false type: string @@ -78,35 +78,42 @@ jobs: lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} + setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} + setup-span-id: ${{ steps.setup.outputs.span-id }} setup-trace-id: ${{ steps.setup.outputs.trace-id }} stale_lock_file_failed: ${{ steps.check-lock-file.outputs.stale_lock_file_failed == 'true' }} steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@239aec45b78c8799417efdd5bc6d8cc036629ec1 # v0.71.1 + uses: github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} + env: + GH_AW_SETUP_WORKFLOW_NAME: "CI Post-Mortem Analysis" + GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/ci-postmortem.lock.yml@${{ github.ref }} + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Generate agentic run info id: generate_aw_info env: GH_AW_INFO_ENGINE_ID: "copilot" GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" GH_AW_INFO_MODEL: "claude-sonnet-4.5" - GH_AW_INFO_VERSION: "1.0.35" - GH_AW_INFO_AGENT_VERSION: "1.0.35" - GH_AW_INFO_CLI_VERSION: "v0.71.1" + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_AGENT_VERSION: "1.0.48" + GH_AW_INFO_CLI_VERSION: "v0.74.8" GH_AW_INFO_WORKFLOW_NAME: "CI Post-Mortem Analysis" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" GH_AW_INFO_STAGED: "false" GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","dotnet","github","aka.ms","dev.azure.com","devdiv.visualstudio.com","microsoft.com","vsassets.io"]' GH_AW_INFO_FIREWALL_ENABLED: "true" - GH_AW_INFO_AWF_VERSION: "v0.25.28" + GH_AW_INFO_AWF_VERSION: "v0.25.49" GH_AW_INFO_AWMG_VERSION: "" GH_AW_INFO_FIREWALL_TYPE: "squid" GH_AW_COMPILED_STRICT: "true" - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -130,17 +137,18 @@ jobs: .crush .gemini .opencode + .pi sparse-checkout-cone-mode: true fetch-depth: 1 - name: Save agent config folders for base branch restoration env: - GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode" - GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md opencode.jsonc" + GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi" + GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc" # poutine:ignore untrusted_checkout_exec run: bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh" - name: Check workflow lock file id: check-lock-file - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_WORKFLOW_FILE: "ci-postmortem.lock.yml" GH_AW_CONTEXT_WORKFLOW_REF: "${{ github.workflow_ref }}" @@ -151,9 +159,9 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/check_workflow_timestamp_api.cjs'); await main(); - name: Check compile-agentic version - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: - GH_AW_COMPILED_VERSION: "v0.71.1" + GH_AW_COMPILED_VERSION: "v0.74.8" with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -164,11 +172,11 @@ jobs: env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl + GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }} GH_AW_GITHUB_ACTOR: ${{ github.actor }} - GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} @@ -187,30 +195,33 @@ jobs: Tools: add_comment(max:20), create_issue(max:20), update_issue(max:20), missing_tool, missing_data, noop + GH_AW_PROMPT_956c986f1e45d6a0_EOF + cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md" + cat << 'GH_AW_PROMPT_956c986f1e45d6a0_EOF' The following GitHub context information is available for this workflow: - {{#if __GH_AW_GITHUB_ACTOR__ }} + {{#if github.actor}} - **actor**: __GH_AW_GITHUB_ACTOR__ {{/if}} - {{#if __GH_AW_GITHUB_REPOSITORY__ }} + {{#if github.repository}} - **repository**: __GH_AW_GITHUB_REPOSITORY__ {{/if}} - {{#if __GH_AW_GITHUB_WORKSPACE__ }} + {{#if github.workspace}} - **workspace**: __GH_AW_GITHUB_WORKSPACE__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }} - - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ + {{#if github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)}} + - **issue-number**: #__GH_AW_EXPR_802A9F6A__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }} - - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ + {{#if github.event.discussion.number || (github.aw.context.item_type == 'discussion' && github.aw.context.item_number)}} + - **discussion-number**: #__GH_AW_EXPR_1A3A194A__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }} - - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ + {{#if github.event.pull_request.number || (github.aw.context.item_type == 'pull_request' && github.aw.context.item_number)}} + - **pull-request-number**: #__GH_AW_EXPR_463A214A__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }} - - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__ + {{#if github.event.comment.id || github.aw.context.comment_id}} + - **comment-id**: __GH_AW_EXPR_FF1D34CE__ {{/if}} - {{#if __GH_AW_GITHUB_RUN_ID__ }} + {{#if github.run_id}} - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__ {{/if}} @@ -223,9 +234,10 @@ jobs: GH_AW_PROMPT_956c986f1e45d6a0_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_ENGINE_ID: "copilot" with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -233,17 +245,18 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/interpolate_prompt.cjs'); await main(); - name: Substitute placeholders - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }} GH_AW_GITHUB_ACTOR: ${{ github.actor }} - GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} + GH_AW_MCP_CLI_SERVERS_LIST: '- `safeoutputs` — run `safeoutputs --help` to see available tools' with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -255,14 +268,15 @@ jobs: return await substitutePlaceholders({ file: process.env.GH_AW_PROMPT, substitutions: { + GH_AW_EXPR_1A3A194A: process.env.GH_AW_EXPR_1A3A194A, + GH_AW_EXPR_463A214A: process.env.GH_AW_EXPR_463A214A, + GH_AW_EXPR_802A9F6A: process.env.GH_AW_EXPR_802A9F6A, + GH_AW_EXPR_FF1D34CE: process.env.GH_AW_EXPR_FF1D34CE, GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, - GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID, - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER, - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER, - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER, GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY, GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID, - GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE + GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE, + GH_AW_MCP_CLI_SERVERS_LIST: process.env.GH_AW_MCP_CLI_SERVERS_LIST } }); - name: Validate prompt placeholders @@ -280,11 +294,15 @@ jobs: uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: activation + include-hidden-files: true path: | /tmp/gh-aw/aw_info.json /tmp/gh-aw/aw-prompts/prompt.txt + /tmp/gh-aw/aw-prompts/prompt-template.txt + /tmp/gh-aw/aw-prompts/prompt-import-tree.json /tmp/gh-aw/github_rate_limits.jsonl /tmp/gh-aw/base + /tmp/gh-aw/.github/agents if-no-files-found: ignore retention-days: 1 @@ -307,6 +325,7 @@ jobs: agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }} checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }} + effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }} has_patch: ${{ steps.collect_output.outputs.has_patch }} inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }} mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }} @@ -314,15 +333,23 @@ jobs: model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }} output: ${{ steps.collect_output.outputs.output }} output_types: ${{ steps.collect_output.outputs.output_types }} + setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} + setup-span-id: ${{ steps.setup.outputs.span-id }} setup-trace-id: ${{ steps.setup.outputs.trace-id }} steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@239aec45b78c8799417efdd5bc6d8cc036629ec1 # v0.71.1 + uses: github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} + env: + GH_AW_SETUP_WORKFLOW_NAME: "CI Post-Mortem Analysis" + GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/ci-postmortem.lock.yml@${{ github.ref }} + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Set runtime paths id: set-runtime-paths run: | @@ -358,7 +385,7 @@ jobs: id: checkout-pr if: | github.event.pull_request || github.event.issue.pull_request - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} with: @@ -369,11 +396,11 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); await main(); - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.35 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48 env: GH_HOST: github.com - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.28 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.49 - name: Parse integrity filter lists id: parse-guard-vars env: @@ -389,12 +416,17 @@ jobs: - name: Restore agent config folders from base branch if: steps.checkout-pr.outcome == 'success' env: - GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode" - GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md opencode.jsonc" + GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi" + GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh" + - name: Restore inline sub-agents from activation artifact + env: + GH_AW_SUB_AGENT_DIR: ".github/agents" + GH_AW_SUB_AGENT_EXT: ".agent.md" + run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh" - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.28@sha256:a8834e285807654bf680154faa710d43fe4365a0868142f5c20e48c85e137a7a ghcr.io/github/gh-aw-firewall/api-proxy:0.25.28@sha256:93290f2393752252911bd7c39a047f776c0b53063575e7bde4e304962a9a61cb ghcr.io/github/gh-aw-firewall/squid:0.25.28@sha256:844c18280f82cd1b06345eb2f4e91966b34185bfc51c9f237c3e022e848fb474 ghcr.io/github/gh-aw-mcpg:v0.3.0@sha256:9c2228324fb1f26f39dc9471612e530ae3efc3156dac05efb2e8d212878d454d ghcr.io/github/github-mcp-server:v1.0.2@sha256:26db03408086a99cf1916348dcc4f9614206658f9082a8060dc7c81ad787f4ba node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f - - name: Write Safe Outputs Config + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.49 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.49 ghcr.io/github/gh-aw-firewall/squid:0.25.49 ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388 ghcr.io/github/github-mcp-server:v1.0.4 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f + - name: Generate Safe Outputs Config run: | mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs @@ -402,7 +434,7 @@ jobs: cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_c2d474e65378a915_EOF' {"add_comment":{"max":20},"create_issue":{"max":20},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{},"update_issue":{"allow_body":true,"max":20}} GH_AW_SAFE_OUTPUTS_CONFIG_c2d474e65378a915_EOF - - name: Write Safe Outputs Tools + - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | { @@ -447,6 +479,9 @@ jobs: "sanitize": true, "maxLength": 65000 }, + "fields": { + "type": "array" + }, "labels": { "type": "array", "itemType": "string", @@ -599,7 +634,7 @@ jobs: "customValidation": "requiresOneOf:status,title,body" } } - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -660,6 +695,7 @@ jobs: # Export gateway environment variables for MCP config and gateway script export MCP_GATEWAY_PORT="8080" export MCP_GATEWAY_DOMAIN="host.docker.internal" + export MCP_GATEWAY_HOST_DOMAIN="localhost" MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=') echo "::add-mask::${MCP_GATEWAY_API_KEY}" export MCP_GATEWAY_API_KEY @@ -671,8 +707,13 @@ jobs: export GH_AW_ENGINE="copilot" MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0') MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0') - DOCKER_SOCK_GID=$(stat -c '%g' /var/run/docker.sock 2>/dev/null || echo '0') - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.0' + case "${DOCKER_HOST:-}" in + unix://* ) DOCKER_SOCK_PATH="${DOCKER_HOST#unix://}" ;; + /* ) DOCKER_SOCK_PATH="$DOCKER_HOST" ;; + * ) DOCKER_SOCK_PATH=/var/run/docker.sock ;; + esac + DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0') + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.9' mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) @@ -681,7 +722,7 @@ jobs: "mcpServers": { "github": { "type": "stdio", - "container": "ghcr.io/github/github-mcp-server:v1.0.2", + "container": "ghcr.io/github/github-mcp-server:v1.0.4", "env": { "GITHUB_HOST": "\${GITHUB_SERVER_URL}", "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", @@ -721,32 +762,59 @@ jobs: } } GH_AW_MCP_CONFIG_7bd5cd6513b45b21_EOF - - name: Clean git credentials + - name: Mount MCP servers as CLIs + id: mount-mcp-clis + continue-on-error: true + env: + MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }} + MCP_GATEWAY_DOMAIN: ${{ steps.start-mcp-gateway.outputs.gateway-domain }} + MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }} + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/mount_mcp_as_cli.cjs'); + await main(); + - name: Clean credentials continue-on-error: true run: bash "${RUNNER_TEMP}/gh-aw/actions/clean_git_credentials.sh" + - name: Audit pre-agent workspace + id: pre_agent_audit + continue-on-error: true + run: bash "${RUNNER_TEMP}/gh-aw/actions/audit_pre_agent_workspace.sh" - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): timeout-minutes: 20 run: | set -o pipefail + printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt touch /tmp/gh-aw/agent-step-summary.md GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) export GH_AW_NODE_BIN + export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/agent-stdio.log) + printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.49/awf-config.schema.json","network":{"allowDomains":["*.githubusercontent.com","*.vsblob.vsassets.io","aka.ms","api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.nuget.org","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","azuresearch-usnc.nuget.org","azuresearch-ussc.nuget.org","builds.dotnet.microsoft.com","ci.dot.net","codeload.github.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","dc.services.visualstudio.com","dev.azure.com","devdiv.visualstudio.com","dist.nuget.org","docs.github.com","dot.net","dotnet.microsoft.com","dotnetcli.blob.core.windows.net","github-cloud.githubusercontent.com","github-cloud.s3.amazonaws.com","github.blog","github.com","github.githubassets.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","lfs.github.com","microsoft.com","nuget.org","nuget.pkg.github.com","nugetregistryv2prod.blob.core.windows.net","objects.githubusercontent.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","oneocsp.microsoft.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","patch-diff.githubusercontent.com","pkgs.dev.azure.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","vsassets.io","www.googleapis.com","www.microsoft.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5","gemini-pro","haiku","any"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"auto":["large"],"claude":["agent","sonnet-6x","haiku","any"],"codex":["agent","gpt-5-codex","gpt-5","any"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"copilot":["agent","gpt-5.4","sonnet","gpt-5","any"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent","gemini-pro","gemini-flash","any"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite","copilot/raptor*mini*"],"opus":["copilot/*opus*","anthropic/*opus*"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4.5*","copilot/*sonnet-4-5*","anthropic/*sonnet-4.5*","anthropic/*sonnet-4-5*","copilot/*sonnet-3.7*","copilot/*sonnet-3-7*","anthropic/*sonnet-3.7*","anthropic/*sonnet-3-7*","copilot/*sonnet-3.5*","copilot/*sonnet-3-5*","anthropic/*sonnet-3.5*","anthropic/*sonnet-3-5*"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.49"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" + cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" + fi # shellcheck disable=SC1003 - sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --allow-domains '*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,devdiv.visualstudio.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --image-tag 0.25.28,squid=sha256:844c18280f82cd1b06345eb2f4e91966b34185bfc51c9f237c3e022e848fb474,agent=sha256:a8834e285807654bf680154faa710d43fe4365a0868142f5c20e48c85e137a7a,api-proxy=sha256:93290f2393752252911bd7c39a047f776c0b53063575e7bde4e304962a9a61cb,cli-proxy=sha256:fdf310e4678ce58d248c466b89399e9680a3003038fd19322c388559016aaac7 --skip-pull --enable-api-proxy \ - -- /bin/bash -c 'GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || echo node)"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_driver.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ + -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: + AWF_REFLECT_ENABLED: 1 COPILOT_AGENT_RUNNER_TYPE: STANDALONE - COPILOT_API_KEY: dummy-byok-key-for-offline-mode + COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} COPILOT_MODEL: claude-sonnet-4.5 GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_VERSION: v0.71.1 + GH_AW_VERSION: v0.74.8 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows @@ -794,7 +862,7 @@ jobs: bash "${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh" "$GATEWAY_PID" - name: Redact secrets in logs if: always() - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -820,10 +888,10 @@ jobs: - name: Ingest agent output id: collect_output if: always() - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,devdiv.visualstudio.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,devdiv.visualstudio.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} with: @@ -834,7 +902,7 @@ jobs: await main(); - name: Parse agent logs for step summary if: always() - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/ with: @@ -846,7 +914,7 @@ jobs: - name: Parse MCP Gateway logs for step summary if: always() id: parse-mcp-gateway - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -861,7 +929,7 @@ jobs: run: | # Fix permissions on firewall logs/audit dirs so they can be uploaded as artifacts # AWF runs with sudo, creating files owned by root - sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall 2>/dev/null || true + sudo chmod -R a+rX /tmp/gh-aw/sandbox/firewall 2>/dev/null || true # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step) if command -v awf &> /dev/null; then awf logs summary | tee -a "$GITHUB_STEP_SUMMARY" @@ -871,13 +939,23 @@ jobs: - name: Parse token usage for step summary if: always() continue-on-error: true - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); setupGlobals(core, github, context, exec, io, getOctokit); const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_token_usage.cjs'); await main(); + - name: Print AWF reflect summary + if: always() + continue-on-error: true + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/awf_reflect_summary.cjs'); + await main(); - name: Write agent output placeholder if missing if: always() run: | @@ -899,14 +977,17 @@ jobs: !/tmp/gh-aw/proxy-logs/proxy-tls/ /tmp/gh-aw/agent_usage.json /tmp/gh-aw/agent-stdio.log + /tmp/gh-aw/pre-agent-audit.txt /tmp/gh-aw/agent/ /tmp/gh-aw/github_rate_limits.jsonl /tmp/gh-aw/safeoutputs.jsonl /tmp/gh-aw/agent_output.json /tmp/gh-aw/aw-*.patch /tmp/gh-aw/aw-*.bundle + /tmp/gh-aw/awf-config.json /tmp/gh-aw/sandbox/firewall/logs/ /tmp/gh-aw/sandbox/firewall/audit/ + /tmp/gh-aw/sandbox/firewall/awf-reflect.json if-no-files-found: ignore conclusion: @@ -927,6 +1008,7 @@ jobs: concurrency: group: "gh-aw-conclusion-ci-postmortem" cancel-in-progress: false + queue: max outputs: incomplete_count: ${{ steps.report_incomplete.outputs.incomplete_count }} noop_message: ${{ steps.noop.outputs.noop_message }} @@ -935,11 +1017,17 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@239aec45b78c8799417efdd5bc6d8cc036629ec1 # v0.71.1 + uses: github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} + env: + GH_AW_SETUP_WORKFLOW_NAME: "CI Post-Mortem Analysis" + GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/ci-postmortem.lock.yml@${{ github.ref }} + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -956,7 +1044,7 @@ jobs: echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" - name: Process no-op messages id: noop - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_NOOP_MAX: "1" @@ -973,7 +1061,7 @@ jobs: await main(); - name: Log detection run id: detection_runs - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "CI Post-Mortem Analysis" @@ -989,7 +1077,7 @@ jobs: await main(); - name: Record missing tool id: missing_tool - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_MISSING_TOOL_CREATE_ISSUE: "true" @@ -1003,7 +1091,7 @@ jobs: await main(); - name: Record incomplete id: report_incomplete - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true" @@ -1018,7 +1106,7 @@ jobs: - name: Handle agent failure id: handle_agent_failure if: always() - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "CI Post-Mortem Analysis" @@ -1029,15 +1117,21 @@ jobs: GH_AW_ENGINE_ID: "copilot" GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} + GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens || '' }} + GH_AW_EFFECTIVE_TOKENS_RATE_LIMIT_ERROR: ${{ needs.agent.outputs.effective_tokens_rate_limit_error || 'false' }} GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }} GH_AW_MCP_POLICY_ERROR: ${{ needs.agent.outputs.mcp_policy_error }} GH_AW_AGENTIC_ENGINE_TIMEOUT: ${{ needs.agent.outputs.agentic_engine_timeout }} GH_AW_MODEL_NOT_SUPPORTED_ERROR: ${{ needs.agent.outputs.model_not_supported_error }} + GH_AW_ENGINE_API_HOSTS: "api.enterprise.githubcopilot.com,api.githubcopilot.com,api.business.githubcopilot.com,api.individual.githubcopilot.com" GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }} GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} GH_AW_GROUP_REPORTS: "false" GH_AW_FAILURE_REPORT_AS_ISSUE: "true" + GH_AW_MISSING_TOOL_REPORT_AS_FAILURE: "true" + GH_AW_MISSING_DATA_REPORT_AS_FAILURE: "true" GH_AW_TIMEOUT_MINUTES: "20" + GH_AW_MAX_EFFECTIVE_TOKENS: "25000000" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1062,11 +1156,17 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@239aec45b78c8799417efdd5bc6d8cc036629ec1 # v0.71.1 + uses: github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} + env: + GH_AW_SETUP_WORKFLOW_NAME: "CI Post-Mortem Analysis" + GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/ci-postmortem.lock.yml@${{ github.ref }} + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -1092,7 +1192,7 @@ jobs: rm -rf /tmp/gh-aw/sandbox/firewall/logs rm -rf /tmp/gh-aw/sandbox/firewall/audit - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.28@sha256:a8834e285807654bf680154faa710d43fe4365a0868142f5c20e48c85e137a7a ghcr.io/github/gh-aw-firewall/api-proxy:0.25.28@sha256:93290f2393752252911bd7c39a047f776c0b53063575e7bde4e304962a9a61cb ghcr.io/github/gh-aw-firewall/squid:0.25.28@sha256:844c18280f82cd1b06345eb2f4e91966b34185bfc51c9f237c3e022e848fb474 + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.49 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.49 ghcr.io/github/gh-aw-firewall/squid:0.25.49 - name: Check if detection needed id: detection_guard if: always() @@ -1107,7 +1207,7 @@ jobs: echo "run_detection=false" >> "$GITHUB_OUTPUT" echo "Detection skipped: no agent outputs or patches to analyze" fi - - name: Clear MCP configuration for detection + - name: Clear MCP Config for detection if: always() && steps.detection_guard.outputs.run_detection == 'true' run: | rm -f "${RUNNER_TEMP}/gh-aw/mcp-config/mcp-servers.json" @@ -1129,7 +1229,7 @@ jobs: ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true - name: Setup threat detection if: always() && steps.detection_guard.outputs.run_detection == 'true' - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: WORKFLOW_NAME: "CI Post-Mortem Analysis" WORKFLOW_DESCRIPTION: "No description provided" @@ -1151,33 +1251,43 @@ jobs: node-version: '24' package-manager-cache: false - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.35 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48 env: GH_HOST: github.com - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.28 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.49 - name: Execute GitHub Copilot CLI if: always() && steps.detection_guard.outputs.run_detection == 'true' + continue-on-error: true id: detection_agentic_execution # Copilot CLI tool arguments (sorted): timeout-minutes: 20 run: | set -o pipefail + printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt touch /tmp/gh-aw/agent-step-summary.md GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) export GH_AW_NODE_BIN + export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log) + printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.49/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.49"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" + cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" + fi # shellcheck disable=SC1003 - sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,telemetry.enterprise.githubcopilot.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --image-tag 0.25.28,squid=sha256:844c18280f82cd1b06345eb2f4e91966b34185bfc51c9f237c3e022e848fb474,agent=sha256:a8834e285807654bf680154faa710d43fe4365a0868142f5c20e48c85e137a7a,api-proxy=sha256:93290f2393752252911bd7c39a047f776c0b53063575e7bde4e304962a9a61cb,cli-proxy=sha256:fdf310e4678ce58d248c466b89399e9680a3003038fd19322c388559016aaac7 --skip-pull --enable-api-proxy \ - -- /bin/bash -c 'GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || echo node)"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_driver.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ + -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log env: + AWF_REFLECT_ENABLED: 1 COPILOT_AGENT_RUNNER_TYPE: STANDALONE - COPILOT_API_KEY: dummy-byok-key-for-offline-mode + COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} COPILOT_MODEL: claude-sonnet-4.5 GH_AW_PHASE: detection GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_VERSION: v0.71.1 + GH_AW_VERSION: v0.74.8 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows @@ -1201,16 +1311,35 @@ jobs: - name: Parse and conclude threat detection id: detection_conclusion if: always() - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + continue-on-error: true + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} + DETECTION_AGENTIC_EXECUTION_OUTCOME: ${{ steps.detection_agentic_execution.outcome }} GH_AW_DETECTION_CONTINUE_ON_ERROR: "true" with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_threat_detection_results.cjs'); - await main(); + try { + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_threat_detection_results.cjs'); + await main(); + } catch (loadErr) { + const continueOnError = process.env.GH_AW_DETECTION_CONTINUE_ON_ERROR !== 'false'; + const detectionExecutionFailed = process.env.DETECTION_AGENTIC_EXECUTION_OUTCOME === 'failure'; + const msg = 'ERR_SYSTEM: \u274C Unexpected error loading threat detection module: ' + (loadErr && loadErr.message ? loadErr.message : String(loadErr)); + core.error(msg); + core.setOutput('reason', 'parse_error'); + if (continueOnError && !detectionExecutionFailed) { + core.warning('\u26A0\uFE0F ' + msg); + core.setOutput('conclusion', 'warning'); + core.setOutput('success', 'false'); + } else { + core.setOutput('conclusion', 'failure'); + core.setOutput('success', 'false'); + core.setFailed(msg); + } + } safe_outputs: needs: @@ -1232,7 +1361,7 @@ jobs: GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }} GH_AW_ENGINE_ID: "copilot" GH_AW_ENGINE_MODEL: "claude-sonnet-4.5" - GH_AW_ENGINE_VERSION: "1.0.35" + GH_AW_ENGINE_VERSION: "1.0.48" GH_AW_WORKFLOW_ID: "ci-postmortem" GH_AW_WORKFLOW_NAME: "CI Post-Mortem Analysis" outputs: @@ -1249,11 +1378,17 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@239aec45b78c8799417efdd5bc6d8cc036629ec1 # v0.71.1 + uses: github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} + env: + GH_AW_SETUP_WORKFLOW_NAME: "CI Post-Mortem Analysis" + GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/ci-postmortem.lock.yml@${{ github.ref }} + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -1279,10 +1414,11 @@ jobs: echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV" - name: Process Safe Outputs id: process_safe_outputs - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,devdiv.visualstudio.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" + GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }} + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,devdiv.visualstudio.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":20},\"create_issue\":{\"max\":20},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{},\"update_issue\":{\"allow_body\":true,\"max\":20}}" diff --git a/.github/workflows/code-radiator.lock.yml b/.github/workflows/code-radiator.lock.yml index 8c0f8d46a7c0..cd32f396e575 100644 --- a/.github/workflows/code-radiator.lock.yml +++ b/.github/workflows/code-radiator.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"a665debda1a902047622496aa625b015b0b9f053d3892454a63ac7b73cc61808","compiler_version":"v0.72.1","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-4.5"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"bc56a0cad2f450c562810785ef38649c04db812a","version":"v0.72.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.41","digest":"sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.25.41@sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41","digest":"sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41@sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.41","digest":"sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.25.41@sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.6","digest":"sha256:2bb8eef86006a4c5963c55616a9c51c32f27bfdecb023b8aa6f91f6718d9171c","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.6@sha256:2bb8eef86006a4c5963c55616a9c51c32f27bfdecb023b8aa6f91f6718d9171c"},{"image":"ghcr.io/github/github-mcp-server:v1.0.3","digest":"sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959","pinned_image":"ghcr.io/github/github-mcp-server:v1.0.3@sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"a665debda1a902047622496aa625b015b0b9f053d3892454a63ac7b73cc61808","compiler_version":"v0.74.8","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-4.5"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"efa55847f72aadb03490d955263ff911bf758700","version":"v0.74.8"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.49"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.49"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.49"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.9","digest":"sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388"},{"image":"ghcr.io/github/github-mcp-server:v1.0.4"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -14,7 +14,7 @@ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ # -# This file was automatically generated by gh-aw (v0.72.1). DO NOT EDIT. +# This file was automatically generated by gh-aw (v0.74.8). DO NOT EDIT. # # To update this file, edit the corresponding .md file and run: # gh aw compile @@ -36,18 +36,18 @@ # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 # - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 -# - github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 +# - github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 # # Container images used: -# - ghcr.io/github/gh-aw-firewall/agent:0.25.41@sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770 -# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41@sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0 -# - ghcr.io/github/gh-aw-firewall/squid:0.25.41@sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4 -# - ghcr.io/github/gh-aw-mcpg:v0.3.6@sha256:2bb8eef86006a4c5963c55616a9c51c32f27bfdecb023b8aa6f91f6718d9171c -# - ghcr.io/github/github-mcp-server:v1.0.3@sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959 +# - ghcr.io/github/gh-aw-firewall/agent:0.25.49 +# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.49 +# - ghcr.io/github/gh-aw-firewall/squid:0.25.49 +# - ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388 +# - ghcr.io/github/github-mcp-server:v1.0.4 # - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f name: "Code Radiator" -"on": +on: # roles: # Roles processed as role check in pre-activation job # - admin # Roles processed as role check in pre-activation job # - maintain # Roles processed as role check in pre-activation job @@ -59,7 +59,7 @@ name: "Code Radiator" inputs: aw_context: default: "" - description: Agent caller context (used internally by Agentic Workflows). + description: "Agent caller context (used internally by Agentic Workflows)." required: false type: string @@ -84,35 +84,38 @@ jobs: lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} + setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} + setup-span-id: ${{ steps.setup.outputs.span-id }} setup-trace-id: ${{ steps.setup.outputs.trace-id }} stale_lock_file_failed: ${{ steps.check-lock-file.outputs.stale_lock_file_failed == 'true' }} steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} env: GH_AW_SETUP_WORKFLOW_NAME: "Code Radiator" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/code-radiator.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Generate agentic run info id: generate_aw_info env: GH_AW_INFO_ENGINE_ID: "copilot" GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" GH_AW_INFO_MODEL: "claude-sonnet-4.5" - GH_AW_INFO_VERSION: "1.0.40" - GH_AW_INFO_AGENT_VERSION: "1.0.40" - GH_AW_INFO_CLI_VERSION: "v0.72.1" + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_AGENT_VERSION: "1.0.48" + GH_AW_INFO_CLI_VERSION: "v0.74.8" GH_AW_INFO_WORKFLOW_NAME: "Code Radiator" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" GH_AW_INFO_STAGED: "false" GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","github"]' GH_AW_INFO_FIREWALL_ENABLED: "true" - GH_AW_INFO_AWF_VERSION: "v0.25.41" + GH_AW_INFO_AWF_VERSION: "v0.25.49" GH_AW_INFO_AWMG_VERSION: "" GH_AW_INFO_FIREWALL_TYPE: "squid" GH_AW_COMPILED_STRICT: "true" @@ -164,7 +167,7 @@ jobs: - name: Check compile-agentic version uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: - GH_AW_COMPILED_VERSION: "v0.72.1" + GH_AW_COMPILED_VERSION: "v0.74.8" with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -175,11 +178,11 @@ jobs: env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl + GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }} GH_AW_GITHUB_ACTOR: ${{ github.actor }} - GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} @@ -207,28 +210,28 @@ jobs: cat << 'GH_AW_PROMPT_0170a78c8d56645a_EOF' The following GitHub context information is available for this workflow: - {{#if __GH_AW_GITHUB_ACTOR__ }} + {{#if github.actor}} - **actor**: __GH_AW_GITHUB_ACTOR__ {{/if}} - {{#if __GH_AW_GITHUB_REPOSITORY__ }} + {{#if github.repository}} - **repository**: __GH_AW_GITHUB_REPOSITORY__ {{/if}} - {{#if __GH_AW_GITHUB_WORKSPACE__ }} + {{#if github.workspace}} - **workspace**: __GH_AW_GITHUB_WORKSPACE__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }} - - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ + {{#if github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)}} + - **issue-number**: #__GH_AW_EXPR_802A9F6A__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }} - - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ + {{#if github.event.discussion.number || (github.aw.context.item_type == 'discussion' && github.aw.context.item_number)}} + - **discussion-number**: #__GH_AW_EXPR_1A3A194A__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }} - - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ + {{#if github.event.pull_request.number || (github.aw.context.item_type == 'pull_request' && github.aw.context.item_number)}} + - **pull-request-number**: #__GH_AW_EXPR_463A214A__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }} - - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__ + {{#if github.event.comment.id || github.aw.context.comment_id}} + - **comment-id**: __GH_AW_EXPR_FF1D34CE__ {{/if}} - {{#if __GH_AW_GITHUB_RUN_ID__ }} + {{#if github.run_id}} - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__ {{/if}} - **checkouts**: The following repositories have been checked out and are available in the workspace: @@ -258,11 +261,11 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }} GH_AW_GITHUB_ACTOR: ${{ github.actor }} - GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} @@ -278,11 +281,11 @@ jobs: return await substitutePlaceholders({ file: process.env.GH_AW_PROMPT, substitutions: { + GH_AW_EXPR_1A3A194A: process.env.GH_AW_EXPR_1A3A194A, + GH_AW_EXPR_463A214A: process.env.GH_AW_EXPR_463A214A, + GH_AW_EXPR_802A9F6A: process.env.GH_AW_EXPR_802A9F6A, + GH_AW_EXPR_FF1D34CE: process.env.GH_AW_EXPR_FF1D34CE, GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, - GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID, - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER, - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER, - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER, GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY, GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID, GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE, @@ -335,6 +338,7 @@ jobs: agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }} checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }} + effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }} has_patch: ${{ steps.collect_output.outputs.has_patch }} inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }} mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }} @@ -342,19 +346,23 @@ jobs: model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }} output: ${{ steps.collect_output.outputs.output }} output_types: ${{ steps.collect_output.outputs.output_types }} + setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} + setup-span-id: ${{ steps.setup.outputs.span-id }} setup-trace-id: ${{ steps.setup.outputs.trace-id }} steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} env: GH_AW_SETUP_WORKFLOW_NAME: "Code Radiator" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/code-radiator.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Set runtime paths id: set-runtime-paths run: | @@ -408,11 +416,11 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); await main(); - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.40 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48 env: GH_HOST: github.com - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.41 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.49 - name: Parse integrity filter lists id: parse-guard-vars env: @@ -437,7 +445,7 @@ jobs: GH_AW_SUB_AGENT_EXT: ".agent.md" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh" - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.41@sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41@sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0 ghcr.io/github/gh-aw-firewall/squid:0.25.41@sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4 ghcr.io/github/gh-aw-mcpg:v0.3.6@sha256:2bb8eef86006a4c5963c55616a9c51c32f27bfdecb023b8aa6f91f6718d9171c ghcr.io/github/github-mcp-server:v1.0.3@sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.49 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.49 ghcr.io/github/gh-aw-firewall/squid:0.25.49 ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388 ghcr.io/github/github-mcp-server:v1.0.4 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f - name: Generate Safe Outputs Config run: | mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" @@ -778,8 +786,13 @@ jobs: export GH_AW_ENGINE="copilot" MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0') MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0') - DOCKER_SOCK_GID=$(stat -c '%g' /var/run/docker.sock 2>/dev/null || echo '0') - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.6' + case "${DOCKER_HOST:-}" in + unix://* ) DOCKER_SOCK_PATH="${DOCKER_HOST#unix://}" ;; + /* ) DOCKER_SOCK_PATH="$DOCKER_HOST" ;; + * ) DOCKER_SOCK_PATH=/var/run/docker.sock ;; + esac + DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0') + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.9' mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) @@ -788,7 +801,7 @@ jobs: "mcpServers": { "github": { "type": "stdio", - "container": "ghcr.io/github/github-mcp-server:v1.0.3", + "container": "ghcr.io/github/github-mcp-server:v1.0.4", "env": { "GITHUB_HOST": "\${GITHUB_SERVER_URL}", "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", @@ -855,25 +868,32 @@ jobs: timeout-minutes: 20 run: | set -o pipefail + printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt touch /tmp/gh-aw/agent-step-summary.md GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) export GH_AW_NODE_BIN + export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/agent-stdio.log) - printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.41/awf-config.schema.json","network":{"allowDomains":["*.githubusercontent.com","api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","codeload.github.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","docs.github.com","github-cloud.githubusercontent.com","github-cloud.s3.amazonaws.com","github.blog","github.com","github.githubassets.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","lfs.github.com","objects.githubusercontent.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"models":{"auto":["large"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash"],"opus":["copilot/*opus*","anthropic/*opus*"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"]}},"container":{"imageTag":"0.25.41,squid=sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4,agent=sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770,api-proxy=sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.49/awf-config.schema.json","network":{"allowDomains":["*.githubusercontent.com","api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","codeload.github.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","docs.github.com","github-cloud.githubusercontent.com","github-cloud.s3.amazonaws.com","github.blog","github.com","github.githubassets.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","lfs.github.com","objects.githubusercontent.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","patch-diff.githubusercontent.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5","gemini-pro","haiku","any"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"auto":["large"],"claude":["agent","sonnet-6x","haiku","any"],"codex":["agent","gpt-5-codex","gpt-5","any"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"copilot":["agent","gpt-5.4","sonnet","gpt-5","any"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent","gemini-pro","gemini-flash","any"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite","copilot/raptor*mini*"],"opus":["copilot/*opus*","anthropic/*opus*"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4.5*","copilot/*sonnet-4-5*","anthropic/*sonnet-4.5*","anthropic/*sonnet-4-5*","copilot/*sonnet-3.7*","copilot/*sonnet-3-7*","anthropic/*sonnet-3.7*","anthropic/*sonnet-3-7*","copilot/*sonnet-3.5*","copilot/*sonnet-3-5*","anthropic/*sonnet-3.5*","anthropic/*sonnet-3-5*"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.49"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" + cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" + fi # shellcheck disable=SC1003 - sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ - -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || echo node)"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ + -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: AWF_REFLECT_ENABLED: 1 COPILOT_AGENT_RUNNER_TYPE: STANDALONE - COPILOT_API_KEY: dummy-byok-key-for-offline-mode + COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} COPILOT_MODEL: claude-sonnet-4.5 GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_VERSION: v0.72.1 + GH_AW_VERSION: v0.74.8 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows @@ -950,7 +970,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} with: @@ -1067,6 +1087,7 @@ jobs: concurrency: group: "gh-aw-conclusion-code-radiator" cancel-in-progress: false + queue: max outputs: incomplete_count: ${{ steps.report_incomplete.outputs.incomplete_count }} noop_message: ${{ steps.noop.outputs.noop_message }} @@ -1075,15 +1096,17 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} env: GH_AW_SETUP_WORKFLOW_NAME: "Code Radiator" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/code-radiator.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -1173,6 +1196,8 @@ jobs: GH_AW_ENGINE_ID: "copilot" GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} + GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens || '' }} + GH_AW_EFFECTIVE_TOKENS_RATE_LIMIT_ERROR: ${{ needs.agent.outputs.effective_tokens_rate_limit_error || 'false' }} GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }} GH_AW_MCP_POLICY_ERROR: ${{ needs.agent.outputs.mcp_policy_error }} GH_AW_AGENTIC_ENGINE_TIMEOUT: ${{ needs.agent.outputs.agentic_engine_timeout }} @@ -1187,6 +1212,7 @@ jobs: GH_AW_MISSING_TOOL_REPORT_AS_FAILURE: "true" GH_AW_MISSING_DATA_REPORT_AS_FAILURE: "true" GH_AW_TIMEOUT_MINUTES: "20" + GH_AW_MAX_EFFECTIVE_TOKENS: "25000000" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1211,15 +1237,17 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} env: GH_AW_SETUP_WORKFLOW_NAME: "Code Radiator" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/code-radiator.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -1245,7 +1273,7 @@ jobs: rm -rf /tmp/gh-aw/sandbox/firewall/logs rm -rf /tmp/gh-aw/sandbox/firewall/audit - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.41@sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41@sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0 ghcr.io/github/gh-aw-firewall/squid:0.25.41@sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4 + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.49 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.49 ghcr.io/github/gh-aw-firewall/squid:0.25.49 - name: Check if detection needed id: detection_guard if: always() @@ -1304,11 +1332,11 @@ jobs: node-version: '24' package-manager-cache: false - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.40 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48 env: GH_HOST: github.com - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.41 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.49 - name: Execute GitHub Copilot CLI if: always() && steps.detection_guard.outputs.run_detection == 'true' continue-on-error: true @@ -1317,23 +1345,30 @@ jobs: timeout-minutes: 20 run: | set -o pipefail + printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt touch /tmp/gh-aw/agent-step-summary.md GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) export GH_AW_NODE_BIN + export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log) - printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.41/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true},"container":{"imageTag":"0.25.41"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.49/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.49"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" + cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" + fi # shellcheck disable=SC1003 - sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ - -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || echo node)"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ + -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log env: AWF_REFLECT_ENABLED: 1 COPILOT_AGENT_RUNNER_TYPE: STANDALONE - COPILOT_API_KEY: dummy-byok-key-for-offline-mode + COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} COPILOT_MODEL: claude-sonnet-4.5 GH_AW_PHASE: detection GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_VERSION: v0.72.1 + GH_AW_VERSION: v0.74.8 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows @@ -1361,6 +1396,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} + DETECTION_AGENTIC_EXECUTION_OUTCOME: ${{ steps.detection_agentic_execution.outcome }} GH_AW_DETECTION_CONTINUE_ON_ERROR: "true" with: script: | @@ -1371,10 +1407,11 @@ jobs: await main(); } catch (loadErr) { const continueOnError = process.env.GH_AW_DETECTION_CONTINUE_ON_ERROR !== 'false'; + const detectionExecutionFailed = process.env.DETECTION_AGENTIC_EXECUTION_OUTCOME === 'failure'; const msg = 'ERR_SYSTEM: \u274C Unexpected error loading threat detection module: ' + (loadErr && loadErr.message ? loadErr.message : String(loadErr)); core.error(msg); core.setOutput('reason', 'parse_error'); - if (continueOnError) { + if (continueOnError && !detectionExecutionFailed) { core.warning('\u26A0\uFE0F ' + msg); core.setOutput('conclusion', 'warning'); core.setOutput('success', 'false'); @@ -1405,7 +1442,7 @@ jobs: GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }} GH_AW_ENGINE_ID: "copilot" GH_AW_ENGINE_MODEL: "claude-sonnet-4.5" - GH_AW_ENGINE_VERSION: "1.0.40" + GH_AW_ENGINE_VERSION: "1.0.48" GH_AW_WORKFLOW_ID: "code-radiator" GH_AW_WORKFLOW_NAME: "Code Radiator" outputs: @@ -1424,15 +1461,17 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} env: GH_AW_SETUP_WORKFLOW_NAME: "Code Radiator" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/code-radiator.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -1476,8 +1515,16 @@ jobs: echo "Extracted base branch from safe output: $BASE_BRANCH" fi fi + - name: Checkout repository (trusted default branch for comment events) + if: ((!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') || (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')) && (github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment') + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: ${{ github.event.repository.default_branch }} + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + persist-credentials: false + fetch-depth: 1 - name: Checkout repository - if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') || (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') + if: ((!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') || (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')) && github.event_name != 'issue_comment' && github.event_name != 'pull_request_review_comment' uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ steps.extract-base-branch.outputs.base-branch || github.base_ref || github.event.pull_request.base.ref || github.ref_name || github.event.repository.default_branch }} @@ -1512,7 +1559,8 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" + GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }} + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":10,\"target\":\"*\"},\"add_labels\":{\"max\":10,\"target\":\"*\"},\"create_pull_request\":{\"allowed_base_branches\":[\"net[0-9]*.0\",\"xcode[0-9]*\",\"xcode[0-9]*.[0-9]*\"],\"max\":10,\"max_patch_files\":100,\"max_patch_size\":1024,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"]},\"create_report_incomplete_issue\":{},\"merge_pull_request\":{\"max\":10},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"if_no_changes\":\"warn\",\"max\":10,\"max_patch_size\":1024,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"target\":\"*\",\"title_prefix\":\"🤖 Merge 'main' =\\u003e '\"},\"report_incomplete\":{},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":true,\"max\":10,\"update_branch\":false}}" diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 0ae42f6f5c4b..f4841a250f76 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -21,6 +21,6 @@ jobs: - name: Checkout repository uses: actions/checkout@v6 - name: Install gh-aw extension - uses: github/gh-aw-actions/setup-cli@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup-cli@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 with: - version: v0.72.1 + version: v0.74.8 diff --git a/.github/workflows/macios-reviewer.lock.yml b/.github/workflows/macios-reviewer.lock.yml index 616d54825de5..28089a715a5d 100644 --- a/.github/workflows/macios-reviewer.lock.yml +++ b/.github/workflows/macios-reviewer.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"a0f64139dbc6fe8697f9fd99f5489155b561c37ec0b13d7eaf30bda56d034e7f","compiler_version":"v0.72.1","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-4.5"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"bc56a0cad2f450c562810785ef38649c04db812a","version":"v0.72.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.41","digest":"sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.25.41@sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41","digest":"sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41@sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.41","digest":"sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.25.41@sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.6","digest":"sha256:2bb8eef86006a4c5963c55616a9c51c32f27bfdecb023b8aa6f91f6718d9171c","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.6@sha256:2bb8eef86006a4c5963c55616a9c51c32f27bfdecb023b8aa6f91f6718d9171c"},{"image":"ghcr.io/github/github-mcp-server:v1.0.3","digest":"sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959","pinned_image":"ghcr.io/github/github-mcp-server:v1.0.3@sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"a0f64139dbc6fe8697f9fd99f5489155b561c37ec0b13d7eaf30bda56d034e7f","compiler_version":"v0.74.8","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-4.5"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"efa55847f72aadb03490d955263ff911bf758700","version":"v0.74.8"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.49"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.49"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.49"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.9","digest":"sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388"},{"image":"ghcr.io/github/github-mcp-server:v1.0.4"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -14,7 +14,7 @@ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ # -# This file was automatically generated by gh-aw (v0.72.1). DO NOT EDIT. +# This file was automatically generated by gh-aw (v0.74.8). DO NOT EDIT. # # To update this file, edit the corresponding .md file and run: # gh aw compile @@ -35,18 +35,18 @@ # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 # - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 -# - github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 +# - github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 # # Container images used: -# - ghcr.io/github/gh-aw-firewall/agent:0.25.41@sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770 -# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41@sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0 -# - ghcr.io/github/gh-aw-firewall/squid:0.25.41@sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4 -# - ghcr.io/github/gh-aw-mcpg:v0.3.6@sha256:2bb8eef86006a4c5963c55616a9c51c32f27bfdecb023b8aa6f91f6718d9171c -# - ghcr.io/github/github-mcp-server:v1.0.3@sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959 +# - ghcr.io/github/gh-aw-firewall/agent:0.25.49 +# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.49 +# - ghcr.io/github/gh-aw-firewall/squid:0.25.49 +# - ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388 +# - ghcr.io/github/github-mcp-server:v1.0.4 # - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f name: ".NET for Apple Platforms PR Reviewer" -"on": +on: issue_comment: types: - created @@ -83,6 +83,8 @@ jobs: lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} + setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} + setup-span-id: ${{ steps.setup.outputs.span-id }} setup-trace-id: ${{ steps.setup.outputs.trace-id }} slash_command: ${{ needs.pre_activation.outputs.matched_command }} stale_lock_file_failed: ${{ steps.check-lock-file.outputs.stale_lock_file_failed == 'true' }} @@ -91,31 +93,33 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.pre_activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.pre_activation.outputs.setup-parent-span-id || needs.pre_activation.outputs.setup-span-id }} env: GH_AW_SETUP_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/macios-reviewer.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Generate agentic run info id: generate_aw_info env: GH_AW_INFO_ENGINE_ID: "copilot" GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" GH_AW_INFO_MODEL: "claude-sonnet-4.5" - GH_AW_INFO_VERSION: "1.0.40" - GH_AW_INFO_AGENT_VERSION: "1.0.40" - GH_AW_INFO_CLI_VERSION: "v0.72.1" + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_AGENT_VERSION: "1.0.48" + GH_AW_INFO_CLI_VERSION: "v0.74.8" GH_AW_INFO_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" GH_AW_INFO_STAGED: "false" GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","dotnet","github","aka.ms","dev.azure.com","microsoft.com","vsassets.io"]' GH_AW_INFO_FIREWALL_ENABLED: "true" - GH_AW_INFO_AWF_VERSION: "v0.25.41" + GH_AW_INFO_AWF_VERSION: "v0.25.49" GH_AW_INFO_AWMG_VERSION: "" GH_AW_INFO_FIREWALL_TYPE: "squid" GH_AW_COMPILED_STRICT: "true" @@ -128,7 +132,7 @@ jobs: await main(core, context); - name: Add eyes reaction for immediate feedback id: react - if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || github.event_name == 'pull_request' && github.event.pull_request.head.repo.id == github.repository_id || github.event_name == 'pull_request_review' && github.event.pull_request.head.repo.id == github.repository_id + if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || github.event_name == 'pull_request' && github.event.pull_request.head.repo.id == github.repository_id uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_REACTION: "eyes" @@ -180,7 +184,7 @@ jobs: - name: Check compile-agentic version uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: - GH_AW_COMPILED_VERSION: "v0.72.1" + GH_AW_COMPILED_VERSION: "v0.74.8" with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -191,7 +195,7 @@ jobs: id: sanitized uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -200,7 +204,7 @@ jobs: await main(); - name: Add comment with workflow run link id: add-comment - if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || github.event_name == 'pull_request' && github.event.pull_request.head.repo.id == github.repository_id || github.event_name == 'pull_request_review' && github.event.pull_request.head.repo.id == github.repository_id + if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || github.event_name == 'pull_request' && github.event.pull_request.head.repo.id == github.repository_id uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" @@ -214,11 +218,11 @@ jobs: env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl + GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }} GH_AW_GITHUB_ACTOR: ${{ github.actor }} - GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} @@ -243,28 +247,28 @@ jobs: cat << 'GH_AW_PROMPT_33adc77fba6f068a_EOF' The following GitHub context information is available for this workflow: - {{#if __GH_AW_GITHUB_ACTOR__ }} + {{#if github.actor}} - **actor**: __GH_AW_GITHUB_ACTOR__ {{/if}} - {{#if __GH_AW_GITHUB_REPOSITORY__ }} + {{#if github.repository}} - **repository**: __GH_AW_GITHUB_REPOSITORY__ {{/if}} - {{#if __GH_AW_GITHUB_WORKSPACE__ }} + {{#if github.workspace}} - **workspace**: __GH_AW_GITHUB_WORKSPACE__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }} - - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ + {{#if github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)}} + - **issue-number**: #__GH_AW_EXPR_802A9F6A__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }} - - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ + {{#if github.event.discussion.number || (github.aw.context.item_type == 'discussion' && github.aw.context.item_number)}} + - **discussion-number**: #__GH_AW_EXPR_1A3A194A__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }} - - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ + {{#if github.event.pull_request.number || (github.aw.context.item_type == 'pull_request' && github.aw.context.item_number)}} + - **pull-request-number**: #__GH_AW_EXPR_463A214A__ {{/if}} - {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }} - - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__ + {{#if github.event.comment.id || github.aw.context.comment_id}} + - **comment-id**: __GH_AW_EXPR_FF1D34CE__ {{/if}} - {{#if __GH_AW_GITHUB_RUN_ID__ }} + {{#if github.run_id}} - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__ {{/if}} @@ -294,11 +298,11 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} + GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }} GH_AW_GITHUB_ACTOR: ${{ github.actor }} - GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} @@ -317,11 +321,11 @@ jobs: return await substitutePlaceholders({ file: process.env.GH_AW_PROMPT, substitutions: { + GH_AW_EXPR_1A3A194A: process.env.GH_AW_EXPR_1A3A194A, + GH_AW_EXPR_463A214A: process.env.GH_AW_EXPR_463A214A, + GH_AW_EXPR_802A9F6A: process.env.GH_AW_EXPR_802A9F6A, + GH_AW_EXPR_FF1D34CE: process.env.GH_AW_EXPR_FF1D34CE, GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, - GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID, - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER, - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER, - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER, GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY, GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID, GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE, @@ -375,6 +379,7 @@ jobs: agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }} checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }} + effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }} has_patch: ${{ steps.collect_output.outputs.has_patch }} inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }} mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }} @@ -382,19 +387,23 @@ jobs: model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }} output: ${{ steps.collect_output.outputs.output }} output_types: ${{ steps.collect_output.outputs.output_types }} + setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} + setup-span-id: ${{ steps.setup.outputs.span-id }} setup-trace-id: ${{ steps.setup.outputs.trace-id }} steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} env: GH_AW_SETUP_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/macios-reviewer.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Set runtime paths id: set-runtime-paths run: | @@ -441,11 +450,11 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); await main(); - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.40 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48 env: GH_HOST: github.com - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.41 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.49 - name: Parse integrity filter lists id: parse-guard-vars env: @@ -470,7 +479,7 @@ jobs: GH_AW_SUB_AGENT_EXT: ".agent.md" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh" - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.41@sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41@sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0 ghcr.io/github/gh-aw-firewall/squid:0.25.41@sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4 ghcr.io/github/gh-aw-mcpg:v0.3.6@sha256:2bb8eef86006a4c5963c55616a9c51c32f27bfdecb023b8aa6f91f6718d9171c ghcr.io/github/github-mcp-server:v1.0.3@sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.49 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.49 ghcr.io/github/gh-aw-firewall/squid:0.25.49 ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388 ghcr.io/github/github-mcp-server:v1.0.4 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f - name: Generate Safe Outputs Config run: | mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" @@ -694,8 +703,13 @@ jobs: export GH_AW_ENGINE="copilot" MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0') MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0') - DOCKER_SOCK_GID=$(stat -c '%g' /var/run/docker.sock 2>/dev/null || echo '0') - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.6' + case "${DOCKER_HOST:-}" in + unix://* ) DOCKER_SOCK_PATH="${DOCKER_HOST#unix://}" ;; + /* ) DOCKER_SOCK_PATH="$DOCKER_HOST" ;; + * ) DOCKER_SOCK_PATH=/var/run/docker.sock ;; + esac + DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0') + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.9' mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) @@ -704,7 +718,7 @@ jobs: "mcpServers": { "github": { "type": "stdio", - "container": "ghcr.io/github/github-mcp-server:v1.0.3", + "container": "ghcr.io/github/github-mcp-server:v1.0.4", "env": { "GITHUB_HOST": "\${GITHUB_SERVER_URL}", "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", @@ -771,25 +785,32 @@ jobs: timeout-minutes: 20 run: | set -o pipefail + printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt touch /tmp/gh-aw/agent-step-summary.md GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) export GH_AW_NODE_BIN + export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/agent-stdio.log) - printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.41/awf-config.schema.json","network":{"allowDomains":["*.githubusercontent.com","*.vsblob.vsassets.io","aka.ms","api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.nuget.org","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","azuresearch-usnc.nuget.org","azuresearch-ussc.nuget.org","builds.dotnet.microsoft.com","ci.dot.net","codeload.github.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","dc.services.visualstudio.com","dev.azure.com","dist.nuget.org","docs.github.com","dot.net","dotnet.microsoft.com","dotnetcli.blob.core.windows.net","github-cloud.githubusercontent.com","github-cloud.s3.amazonaws.com","github.blog","github.com","github.githubassets.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","lfs.github.com","microsoft.com","nuget.org","nuget.pkg.github.com","nugetregistryv2prod.blob.core.windows.net","objects.githubusercontent.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","oneocsp.microsoft.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","pkgs.dev.azure.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","vsassets.io","www.googleapis.com","www.microsoft.com"]},"apiProxy":{"enabled":true,"models":{"auto":["large"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash"],"opus":["copilot/*opus*","anthropic/*opus*"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"]}},"container":{"imageTag":"0.25.41,squid=sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4,agent=sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770,api-proxy=sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.49/awf-config.schema.json","network":{"allowDomains":["*.githubusercontent.com","*.vsblob.vsassets.io","aka.ms","api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.nuget.org","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","azuresearch-usnc.nuget.org","azuresearch-ussc.nuget.org","builds.dotnet.microsoft.com","ci.dot.net","codeload.github.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","dc.services.visualstudio.com","dev.azure.com","dist.nuget.org","docs.github.com","dot.net","dotnet.microsoft.com","dotnetcli.blob.core.windows.net","github-cloud.githubusercontent.com","github-cloud.s3.amazonaws.com","github.blog","github.com","github.githubassets.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","lfs.github.com","microsoft.com","nuget.org","nuget.pkg.github.com","nugetregistryv2prod.blob.core.windows.net","objects.githubusercontent.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","oneocsp.microsoft.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","patch-diff.githubusercontent.com","pkgs.dev.azure.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","vsassets.io","www.googleapis.com","www.microsoft.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5","gemini-pro","haiku","any"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"auto":["large"],"claude":["agent","sonnet-6x","haiku","any"],"codex":["agent","gpt-5-codex","gpt-5","any"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"copilot":["agent","gpt-5.4","sonnet","gpt-5","any"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent","gemini-pro","gemini-flash","any"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite","copilot/raptor*mini*"],"opus":["copilot/*opus*","anthropic/*opus*"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4.5*","copilot/*sonnet-4-5*","anthropic/*sonnet-4.5*","anthropic/*sonnet-4-5*","copilot/*sonnet-3.7*","copilot/*sonnet-3-7*","anthropic/*sonnet-3.7*","anthropic/*sonnet-3-7*","copilot/*sonnet-3.5*","copilot/*sonnet-3-5*","anthropic/*sonnet-3.5*","anthropic/*sonnet-3-5*"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.49"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" + cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" + fi # shellcheck disable=SC1003 - sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ - -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || echo node)"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ + -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: AWF_REFLECT_ENABLED: 1 COPILOT_AGENT_RUNNER_TYPE: STANDALONE - COPILOT_API_KEY: dummy-byok-key-for-offline-mode + COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} COPILOT_MODEL: claude-sonnet-4.5 GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_VERSION: v0.72.1 + GH_AW_VERSION: v0.74.8 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows @@ -866,7 +887,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} GH_AW_COMMAND: review @@ -982,6 +1003,7 @@ jobs: concurrency: group: "gh-aw-conclusion-macios-reviewer" cancel-in-progress: false + queue: max outputs: incomplete_count: ${{ steps.report_incomplete.outputs.incomplete_count }} noop_message: ${{ steps.noop.outputs.noop_message }} @@ -990,15 +1012,17 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} env: GH_AW_SETUP_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/macios-reviewer.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -1088,6 +1112,8 @@ jobs: GH_AW_ENGINE_ID: "copilot" GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} + GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens || '' }} + GH_AW_EFFECTIVE_TOKENS_RATE_LIMIT_ERROR: ${{ needs.agent.outputs.effective_tokens_rate_limit_error || 'false' }} GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }} GH_AW_MCP_POLICY_ERROR: ${{ needs.agent.outputs.mcp_policy_error }} GH_AW_AGENTIC_ENGINE_TIMEOUT: ${{ needs.agent.outputs.agentic_engine_timeout }} @@ -1100,6 +1126,7 @@ jobs: GH_AW_MISSING_TOOL_REPORT_AS_FAILURE: "true" GH_AW_MISSING_DATA_REPORT_AS_FAILURE: "true" GH_AW_TIMEOUT_MINUTES: "20" + GH_AW_MAX_EFFECTIVE_TOKENS: "25000000" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1144,15 +1171,17 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} env: GH_AW_SETUP_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/macios-reviewer.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -1178,7 +1207,7 @@ jobs: rm -rf /tmp/gh-aw/sandbox/firewall/logs rm -rf /tmp/gh-aw/sandbox/firewall/audit - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.41@sha256:cb2b565d070116d4b67e355775340528b5a2c3cb18b2c9049638bcc2df681770 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.41@sha256:fadd0de387209f69a9a7a1b8722bb5e7fdfb80ba9749a5c60f0e4cd7582a74d0 ghcr.io/github/gh-aw-firewall/squid:0.25.41@sha256:1260445d25968dbf3ae70143964177a0e5914cf2ce07a6117f7d3caec6c3e3c4 + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.49 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.49 ghcr.io/github/gh-aw-firewall/squid:0.25.49 - name: Check if detection needed id: detection_guard if: always() @@ -1237,11 +1266,11 @@ jobs: node-version: '24' package-manager-cache: false - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.40 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48 env: GH_HOST: github.com - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.41 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.49 - name: Execute GitHub Copilot CLI if: always() && steps.detection_guard.outputs.run_detection == 'true' continue-on-error: true @@ -1250,23 +1279,30 @@ jobs: timeout-minutes: 20 run: | set -o pipefail + printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt touch /tmp/gh-aw/agent-step-summary.md GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) export GH_AW_NODE_BIN + export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log) - printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.41/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true},"container":{"imageTag":"0.25.41"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.49/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.49"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" + cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" + fi # shellcheck disable=SC1003 - sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ - -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || echo node)"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ + -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log env: AWF_REFLECT_ENABLED: 1 COPILOT_AGENT_RUNNER_TYPE: STANDALONE - COPILOT_API_KEY: dummy-byok-key-for-offline-mode + COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} COPILOT_MODEL: claude-sonnet-4.5 GH_AW_PHASE: detection GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_VERSION: v0.72.1 + GH_AW_VERSION: v0.74.8 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows @@ -1294,6 +1330,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} + DETECTION_AGENTIC_EXECUTION_OUTCOME: ${{ steps.detection_agentic_execution.outcome }} GH_AW_DETECTION_CONTINUE_ON_ERROR: "true" with: script: | @@ -1304,10 +1341,11 @@ jobs: await main(); } catch (loadErr) { const continueOnError = process.env.GH_AW_DETECTION_CONTINUE_ON_ERROR !== 'false'; + const detectionExecutionFailed = process.env.DETECTION_AGENTIC_EXECUTION_OUTCOME === 'failure'; const msg = 'ERR_SYSTEM: \u274C Unexpected error loading threat detection module: ' + (loadErr && loadErr.message ? loadErr.message : String(loadErr)); core.error(msg); core.setOutput('reason', 'parse_error'); - if (continueOnError) { + if (continueOnError && !detectionExecutionFailed) { core.warning('\u26A0\uFE0F ' + msg); core.setOutput('conclusion', 'warning'); core.setOutput('success', 'false'); @@ -1324,18 +1362,21 @@ jobs: outputs: activated: ${{ steps.check_membership.outputs.is_team_member == 'true' && steps.check_command_position.outputs.command_position_ok == 'true' }} matched_command: ${{ steps.check_command_position.outputs.matched_command }} + setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} + setup-span-id: ${{ steps.setup.outputs.span-id }} setup-trace-id: ${{ steps.setup.outputs.trace-id }} steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} env: GH_AW_SETUP_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/macios-reviewer.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Check team membership for command workflow id: check_membership uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -1378,7 +1419,7 @@ jobs: GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }} GH_AW_ENGINE_ID: "copilot" GH_AW_ENGINE_MODEL: "claude-sonnet-4.5" - GH_AW_ENGINE_VERSION: "1.0.40" + GH_AW_ENGINE_VERSION: "1.0.48" GH_AW_WORKFLOW_ID: "macios-reviewer" GH_AW_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" outputs: @@ -1391,15 +1432,17 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@bc56a0cad2f450c562810785ef38649c04db812a # v0.72.1 + uses: github/gh-aw-actions/setup@efa55847f72aadb03490d955263ff911bf758700 # v0.74.8 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} trace-id: ${{ needs.activation.outputs.setup-trace-id }} + parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} env: GH_AW_SETUP_WORKFLOW_NAME: ".NET for Apple Platforms PR Reviewer" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/macios-reviewer.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.40" + GH_AW_INFO_VERSION: "1.0.48" + GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -1428,7 +1471,8 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" + GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }} + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.vsblob.vsassets.io,aka.ms,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dev.azure.com,dist.nuget.org,docs.github.com,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,microsoft.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,vsassets.io,www.googleapis.com,www.microsoft.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_pull_request_review_comment\":{\"max\":50,\"side\":\"RIGHT\"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{},\"submit_pull_request_review\":{\"allowed_events\":[\"COMMENT\",\"REQUEST_CHANGES\"],\"max\":1,\"supersede_older_reviews\":true}}" diff --git a/Directory.Build.props b/Directory.Build.props index d2990a2b1d1d..b76573194f6b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -22,6 +22,8 @@ 6.1.0 4.7.0 4.4.0 + 3.12.0 + 3.6.0 latest diff --git a/Make.config b/Make.config index bffffb9e0711..2c5a01752645 100644 --- a/Make.config +++ b/Make.config @@ -239,7 +239,6 @@ endif # Tell both Xcode and our build logic which Xcode we're using. export DEVELOPER_DIR=$(XCODE_DEVELOPER_ROOT) -export MD_APPLE_SDK_ROOT=$(abspath $(XCODE_DEVELOPER_ROOT)/../..) else # Without Xcode, set placeholder Xcode values but honor XCODE_CHANNEL so we configure bots correctly ifeq ($(XCODE_CHANNEL),Beta) diff --git a/docs/building-apps/build-properties.md b/docs/building-apps/build-properties.md index 45929fa49458..9a4f20c7b4c6 100644 --- a/docs/building-apps/build-properties.md +++ b/docs/building-apps/build-properties.md @@ -580,6 +580,42 @@ See also: * The [AlternateAppIcon](build-items.md#alternateappicon) item group. * The [AppIcon](#appicon) property. +## InlineClassGetHandle + +Controls whether the build system replaces runtime calls to `Class.GetHandle` / +`Class.GetHandleIntrinsic` with direct native references to Objective-C classes +at build time. + +See [docs/code/class-handles.md](../code/class-handles.md) for an overview. + +The valid options are: + +* `compatibility`: Inlines `Class.GetHandle` calls only for types whose declaring + type matches the requested Objective-C class name. +* `strict`: Inlines all `Class.GetHandle` calls unconditionally. Requires using + the static registrar (not the dynamic registrar). +* (empty): Disables inlining of `Class.GetHandle` calls. + +Default value: +* .NET 11+: `strict` when using NativeAOT (`PublishAot=true`), `compatibility` otherwise. +* .NET 10 and earlier: not set (disabled). + +Example: + +```xml + + compatibility + +``` + +Custom behavior for specific Objective-C classes can be set using the [ReferenceNativeSymbol](build-items.md#referencenativesymbols) item group: + +```xml + + + +``` + ## InlineDlfcnMethods Controls whether the build system replaces runtime calls to `ObjCRuntime.Dlfcn` methods with direct native symbol lookups at build time, eliminating the overhead of `dlsym` at runtime. @@ -1532,6 +1568,21 @@ Consider using the unified [AppBundleResourcePrefix](#appbundleresourceprefix) p See also [IPhoneResourcePrefix](#iphoneresourceprefix) and [MonoMacResourcePrefix](#monomacresourceprefix). +## XcodeLocation + +Specifies the location of Xcode. + +When the build searches for Xcode, it's done in this order: + +1. If the `XcodeLocation` property is set, use that. Note that since all environment variables are automatically MSBuild properties as well, it's also possible to set the `XcodeLocation` environment variable for the same effect. +2. If the `MD_APPLE_SDK_ROOT` environment variable is set, use that. +3. If either of the files `~/Library/Preferences/maui/Settings.plist` or `~/Library/Preferences/Xamarin/Settings.plist` exist, and has the property list value `AppleSdkRoot`, use that. +4. Use the system version of Xcode (as determined by executing `xcode-select --print-path`). + +> [!WARNING] +> Support for the `MD_APPLE_SDK_ROOT` environment variable, and the `~/Library/Preferences/maui/Settings.plist` and `~/Library/Preferences/Xamarin/Settings.plist` files, is deprecated and will be removed in the future. +> Going forward, choose which Xcode to use by either making it the system's version of Xcode (either using `xcode-select --switch ...` on the command line, or in Xcode's settings), or by setting the `XcodeLocation` MSBuild property / environment variable. + ## ZipPath The full path to the `zip` command-line tool. diff --git a/docs/code/class-handles.md b/docs/code/class-handles.md new file mode 100644 index 000000000000..48255fb5aa6a --- /dev/null +++ b/docs/code/class-handles.md @@ -0,0 +1,57 @@ +# Objective-C classes + +Objective-C classes can be referenced from managed code in several ways: + +* Calls to Class.GetHandle / GetHandleIntrinsic + +It's highly desirable to use a direct native reference to Objective-C classes when building a mobile app, for a few reasons: + +* It's faster at runtime, and the app is smaller. +* If the referenced Objective-C class comes from a third-party static library, the + native linker can remove it if it's configured to remove unused code + (because the native linker can't see that the class is in fact used + at runtime) unless there's a direct native reference to the class. + +On the other hand there's one scenario when a direct native reference is not desirable: when the native Objective-C class does not exist. + +In order to create a direct native reference to Objective-C classes, we need to know the names of those Objective-C classes. + +## The `InlineClassGetHandle` property + +This behavior is controlled by the `InlineClassGetHandle` MSBuild property, which +can either be enabled or disabled. + +See the [build properties documentation](../building-apps/build-properties.md) for default values. + +## How it works + +During the build we try to collect the following: + +* Any calls to `Class.GetHandle[Intrinsic]` APIs: we try to collect the class name (this might not always succeed, if the class name is not a constant). + +This is further complicated by the fact that we only want to create native +references for managed references that survive trimming. + +So we do the following: + +1. During trimming, two custom linker steps execute: + + * `InlineClassGetHandleStep`: for every call `Class.GetHandle` we've + collected, this step creates a P/Invoke to a native method that will + return the Objective-C class for that symbol (using a direct native + reference), and modifies the code that fetches that symbol to call said + P/Invoke. + +2. After trimming, we figure out which of those symbols survived: + + * For ILTrim: the `_CollectPostILTrimInformation` MSBuild target inspects + the trimmed assemblies and collects all the inlined P/Invokes that + survived. Per-assembly results are cached to speed up incremental builds. + * For NativeAOT: the `_CollectPostNativeAOTTrimInformation` MSBuild target + inspects the native object file (or static library) produced by NativeAOT, + collects all unresolved native references, and filters them against the + Objective-C classes to determine which survived. + +3. The `_PostTrimmingProcessing` MSBuild target takes the surviving symbols + from either path, generates the corresponding native Objective-C code, and + adds it to the list of files to compile and link into the final executable. diff --git a/docs/guides/HowToBranch.md b/docs/guides/HowToBranch.md index ec95a74c03aa..46048712427c 100644 --- a/docs/guides/HowToBranch.md +++ b/docs/guides/HowToBranch.md @@ -20,8 +20,8 @@ sequence of events would be: 3. `dotnet/macios` branches `release/10.0.1xx-preview42` from `net10.0`: ```shell - $ dotnet checkout net10.0 - $ dotnet checkout -b release/10.0.1xx-preview42 + $ git checkout net10.0 + $ git checkout -b release/10.0.1xx-preview42 ``` Note that release candidates will use values such as `rc.1`, `rc.2`, etc. diff --git a/docs/os-onboarding.md b/docs/os-onboarding.md index db4f7364a34f..6bb151226afc 100644 --- a/docs/os-onboarding.md +++ b/docs/os-onboarding.md @@ -20,7 +20,7 @@ This involves: ### Bind new APIs -This is technically optional, because we can release support for a new OS version even if we bind any of the new APIs. +This is technically optional, because we can release support for a new OS version even if we don't bind any of the new APIs. Yet we try to bind most of new APIs, because it's hard to predict what users will need. diff --git a/dotnet/targets/Xamarin.Shared.Sdk.props b/dotnet/targets/Xamarin.Shared.Sdk.props index fc6465f4c1c0..91177e16d2ed 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.props +++ b/dotnet/targets/Xamarin.Shared.Sdk.props @@ -106,6 +106,12 @@ compatibility + + + strict + compatibility + + diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets index 592fafb84321..5c65259da13d 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.targets +++ b/dotnet/targets/Xamarin.Shared.Sdk.targets @@ -682,6 +682,7 @@ @(_BundlerEnvironmentVariables -> 'EnvironmentVariable=Overwrite=%(Overwrite)|%(Identity)=%(Value)') @(_XamarinFrameworkAssemblies -> 'FrameworkAssembly=%(Filename)') Interpreter=$(MtouchInterpreter) + InlineClassGetHandle=$(InlineClassGetHandle) InlineDlfcnMethods=$(InlineDlfcnMethods) IntermediateLinkDir=$(IntermediateLinkDir) IntermediateOutputPath=$(DeviceSpecificIntermediateOutputPath) @@ -716,6 +717,7 @@ TargetArchitectures=$(TargetArchitectures) TargetFramework=$(_ComputedTargetFrameworkMoniker) TypeMapAssemblyName=$(_TypeMapAssemblyName) + TypeMapFilePath=$(_TypeMapFilePath) TypeMapOutputDirectory=$(_TypeMapOutputDirectory) UseLlvm=$(MtouchUseLlvm) Verbosity=$(_BundlerVerbosity) @@ -840,6 +842,7 @@ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true'" Type="Xamarin.Linker.Steps.PreMarkDispatcher" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.ManagedRegistrarStep" Condition="'$(Registrar)' == 'managed-static' Or '$(Registrar)' == 'trimmable-static'" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.TrimmableRegistrarStep" Condition="'$(Registrar)' == 'trimmable-static'" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.InlineClassGetHandleStep" Condition="'$(InlineClassGetHandle)' != '' And '$(InlineClassGetHandle)' != 'disabled'" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.Steps.ListExportedSymbols" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.Steps.PreOutputDispatcher" /> - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.ClassHandleRewriterStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.ClassHandleRewriterStep" Condition="'$(InlineClassGetHandle)' == '' Or '$(InlineClassGetHandle)' == 'disabled'" /> + <_TypeMapFilePath Condition="'$(_TypeMapFilePath)' == ''">$(DeviceSpecificIntermediateOutputPath)type-map.txt @@ -1728,20 +1734,22 @@ <_ILTrimSurvivingNativeSymbolsFile>$(DeviceSpecificIntermediateOutputPath)inlined-dlfcn\iltrim-surviving-native-symbols.txt - <_NativeAOTUnresolvedSymbolsFile>$(DeviceSpecificIntermediateOutputPath)nativeaot-unresolved-symbols.txt <_NativeAOTSurvivingNativeSymbolsFile>$(DeviceSpecificIntermediateOutputPath)nativeaot-surviving-native-symbols.txt + <_ILTrimSurvivingClassesFile>$(DeviceSpecificIntermediateOutputPath)inlined-class-gethandle\iltrim-classes.txt + <_NativeAOTSurvivingClassesFile>$(DeviceSpecificIntermediateOutputPath)inlined-class-gethandle\nativeaot-classes.txt @@ -1750,6 +1758,7 @@ + @@ -1760,12 +1769,17 @@ <_SurvivingNativeSymbolsFile Include="$(_ILTrimSurvivingNativeSymbolsFile)" Condition="Exists('$(_ILTrimSurvivingNativeSymbolsFile)')" /> <_SurvivingNativeSymbolsFile Include="$(_NativeAOTSurvivingNativeSymbolsFile)" Condition="Exists('$(_NativeAOTSurvivingNativeSymbolsFile)')" /> + + <_SurvivingClassesFiles Include="$(_ILTrimSurvivingClassesFile)" Condition="Exists('$(_ILTrimSurvivingClassesFile)')" /> + <_SurvivingClassesFiles Include="$(_NativeAOTSurvivingClassesFile)" Condition="Exists('$(_NativeAOTSurvivingClassesFile)')" /> @@ -1775,8 +1789,15 @@ <_PostTrimmingSourceFiles> $(DeviceSpecificIntermediateOutputPath)posttrim-info-compiled/%(Arch)/%(Filename).o + <_NativeExecutableObjectFiles Include="@(_PostTrimmingSourceFiles -> '%(OutputFile)')" /> + + - <_CompiledPostTrimmingFiles Include="@(_PostTrimmingSourceFiles -> '%(OutputFile)')" /> - <_NativeExecutableObjectFiles Include="@(_CompiledPostTrimmingFiles)" /> - + @@ -1854,7 +1873,7 @@ _ReadAppManifest; _WriteAppManifest; _CompileNativeExecutable; - _PostTrimmingProcessing; + _CompilePostTrimmingFiles; _ReidentifyDynamicLibraries; _AddSwiftLinkerFlags; _ComputeLinkerProperties; @@ -1868,8 +1887,11 @@ Condition="'$(_UseNativeAot)' == 'true'" DependsOnTargets="_ComputePostTrimmingPaths;_CompileNativeExecutable" Inputs="$(NativeObject)" - Outputs="$(_NativeAOTSurvivingNativeSymbolsFile)" + Outputs="$(_NativeAOTSurvivingNativeSymbolsFile);$(_NativeAOTSurvivingClassesFile)" > + + <_NativeAOTUnresolvedSymbolsFile>$(DeviceSpecificIntermediateOutputPath)nativeaot-unresolved-symbols.txt + + + + + diff --git a/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx b/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx index e799cff2ca7f..7b5384199fa6 100644 --- a/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx +++ b/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx @@ -1639,4 +1639,20 @@ Invalid RuntimeLibLinkMode value: '{0}' + + + The environment variable '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + + The environment variable '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + + The settings file '{0}' is deprecated, and will be ignored in .NET 11+. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + + + + The settings file '{0}' is deprecated, and will be ignored. Please use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. + diff --git a/msbuild/Xamarin.MacDev.Tasks/Sdks.cs b/msbuild/Xamarin.MacDev.Tasks/Sdks.cs deleted file mode 100644 index ca04c9c665f1..000000000000 --- a/msbuild/Xamarin.MacDev.Tasks/Sdks.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.IO; - -using Xamarin.Localization.MSBuild; -using Xamarin.Utils; -using Xamarin.MacDev.Tasks; - -#nullable enable - -namespace Xamarin.MacDev { - public static class Sdks { - public static AppleIPhoneSdk IOS { get; private set; } - public static MacOSXSdk MacOS { get; private set; } - public static AppleTVOSSdk TVOS { get; private set; } - - static Sdks () - { - IOS = new AppleIPhoneSdk (AppleSdkSettings.DeveloperRoot, AppleSdkSettings.DeveloperRootVersionPlist); - TVOS = new AppleTVOSSdk (AppleSdkSettings.DeveloperRoot, AppleSdkSettings.DeveloperRootVersionPlist); - MacOS = new MacOSXSdk (AppleSdkSettings.DeveloperRoot, AppleSdkSettings.DeveloperRootVersionPlist); - } - - public static AppleSdk GetSdk (ApplePlatform framework) - { - switch (framework) { - case ApplePlatform.iOS: - return IOS; - case ApplePlatform.TVOS: - return TVOS; - default: - throw new InvalidOperationException (string.Format (MSBStrings.InvalidFramework, framework)); - } - } - - public static AppleSdk GetSdk (string targetFrameworkMoniker) - { - return GetSdk (PlatformFrameworkHelper.GetFramework (targetFrameworkMoniker)); - } - - public static IAppleSdk GetAppleSdk (ApplePlatform framework) - { - switch (framework) { - case ApplePlatform.iOS: - return IOS; - case ApplePlatform.TVOS: - return TVOS; - case ApplePlatform.MacCatalyst: - case ApplePlatform.MacOSX: - return MacOS; - default: - throw new InvalidOperationException (string.Format (MSBStrings.InvalidFramework, framework)); - } - } - - public static IAppleSdk GetAppleSdk (string targetFrameworkMoniker) - { - return GetAppleSdk (PlatformFrameworkHelper.GetFramework (targetFrameworkMoniker)); - } - - } -} diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/CollectPostILTrimInformation.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/CollectPostILTrimInformation.cs index 116ce430cb49..7f2baaad79e3 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/CollectPostILTrimInformation.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/CollectPostILTrimInformation.cs @@ -9,12 +9,15 @@ using Mono.Cecil; +using Xamarin.Bundler; +using Xamarin.Utils; + #nullable enable namespace Xamarin.MacDev.Tasks { /// /// Scans trimmed assemblies to collect information that survived trimming. - /// See docs/code/native-symbols.md for an overview of native symbol handling. + /// See docs/code/native-symbols.md and docs/code/class-handles.md for an overview of native symbol handling. /// public class CollectPostILTrimInformation : XamarinTask { [Required] @@ -26,6 +29,12 @@ public class CollectPostILTrimInformation : XamarinTask { [Required] public string SurvivingNativeSymbolsFile { get; set; } = ""; + /// + /// Output file listing the Class.GetHandle calls that survived trimming. + /// + [Required] + public string SurvivingClassesFile { get; set; } = ""; + /// /// Directory for per-assembly cache files, to avoid re-scanning unchanged assemblies. /// @@ -51,17 +60,17 @@ void CollectSurvivingNativeSymbols () continue; var assemblyName = Path.GetFileNameWithoutExtension (assemblyPath); - var cacheFile = Path.Combine (CacheDirectory, assemblyName + ".dlfcn-symbols.cache"); + var cacheFile = Path.Combine (CacheDirectory, assemblyName + ".internal-symbols.cache"); string []? cachedSymbols = null; if (File.Exists (cacheFile) && File.GetLastWriteTimeUtc (cacheFile) >= File.GetLastWriteTimeUtc (assemblyPath)) { cachedSymbols = File.ReadAllLines (cacheFile); - Log.LogMessage (MessageImportance.Low, "Using cached dlfcn symbols for {0}", assemblyName); + Log.LogMessage (MessageImportance.Low, "Using cached internal symbols for {0}", assemblyName); survivingSymbols.UnionWith (cachedSymbols); } else { var assemblySymbols = new HashSet (); - CollectDlfcnSymbolsFromAssembly (assemblyPath, assemblySymbols); + CollectInternalSymbolsFromAssembly (assemblyPath, assemblySymbols); // Write per-assembly cache (sorted for stability). var sortedAssemblySymbols = assemblySymbols.OrderBy (s => s).ToArray (); @@ -71,29 +80,53 @@ void CollectSurvivingNativeSymbols () } } + WriteSymbolsToFile (this, SurvivingNativeSymbolsFile, FilterToDlfcnSymbols (survivingSymbols)); + WriteSymbolsToFile (this, SurvivingClassesFile, FilterToClassSymbols (survivingSymbols)); + } + + public static void WriteSymbolsToFile (XamarinTask task, string file, IEnumerable unsortedSymbols) + { // Write the combined results only if contents changed (sorted for stability). - var sorted = survivingSymbols.OrderBy (s => s).ToArray (); + var sorted = unsortedSymbols.OrderBy (s => s).ToArray (); - if (File.Exists (SurvivingNativeSymbolsFile)) { - var existing = File.ReadAllLines (SurvivingNativeSymbolsFile); - if (existing.SequenceEqual (sorted)) + if (File.Exists (file)) { + var existing = File.ReadAllLines (file); + if (existing.SequenceEqual (sorted)) { + task.Log.LogMessage (MessageImportance.Low, "The file {0} is already up-to-date with {1} symbols", file, sorted.Length); return; + } } - var dir = Path.GetDirectoryName (SurvivingNativeSymbolsFile); - if (!string.IsNullOrEmpty (dir)) - Directory.CreateDirectory (dir); - File.WriteAllLines (SurvivingNativeSymbolsFile, sorted); - Log.LogMessage (MessageImportance.Low, "Found {0} surviving inlined dlfcn symbols", survivingSymbols.Count); + PathUtils.CreateDirectoryForFile (file); + File.WriteAllLines (file, sorted); + task.Log.LogMessage (MessageImportance.Low, "Wrote {0} symbols to {1}", sorted.Length, file); } - static void CollectDlfcnSymbolsFromAssembly (string assemblyPath, HashSet survivingSymbols) + public static IEnumerable FilterToDlfcnSymbols (IEnumerable symbols) { - const string prefix = "xamarin_Dlfcn_"; - const string suffix = "_Native"; + return FilterTo (symbols, "_xamarin_Dlfcn_", "_Native"); + } + public static IEnumerable FilterToClassSymbols (IEnumerable symbols) + { + return FilterTo (symbols, "_xamarin_Class_GetHandle_", "_Native"); + } + + static IEnumerable FilterTo (IEnumerable symbols, string prefix, string suffix) + { + return symbols + .Where (symbol => symbol.StartsWith (prefix, StringComparison.Ordinal) && symbol.EndsWith (suffix, StringComparison.Ordinal)) + .Select (symbol => symbol.Substring (prefix.Length, symbol.Length - prefix.Length - suffix.Length)); + } + + static void CollectInternalSymbolsFromAssembly (string assemblyPath, HashSet survivingSymbols) + { using var assembly = AssemblyDefinition.ReadAssembly (assemblyPath, new ReaderParameters { ReadSymbols = false }); foreach (var module in assembly.Modules) { + if (!module.HasModuleReferences) + continue; + if (!module.ModuleReferences.Any (mr => mr.Name == "__Internal")) + continue; foreach (var type in module.Types) { if (!type.HasMethods) continue; @@ -102,14 +135,7 @@ static void CollectDlfcnSymbolsFromAssembly (string assemblyPath, HashSet v))); return false; } @@ -252,7 +252,7 @@ bool SetMinimumOSVersion (PDictionary plist) var minimumiOSVersionInManifest = plist.Get (ManifestKeys.MinimumOSVersion)?.Value; if (!string.IsNullOrEmpty (minimumiOSVersionInManifest)) { // Convert to the macOS version - if (!MacCatalystSupport.TryGetMacOSVersion (Sdks.GetAppleSdk (Platform).GetSdkPath (SdkVersion), minimumiOSVersionInManifest!, out var convertedVersion, out var knowniOSVersions)) { + if (!MacCatalystSupport.TryGetMacOSVersion (CurrentSdk.GetSdkPath (SdkVersion), minimumiOSVersionInManifest!, out var convertedVersion, out var knowniOSVersions)) { Log.LogError (MSBStrings.E0188, minimumiOSVersionInManifest, string.Join (", ", knowniOSVersions.OrderBy (v => v))); return false; } @@ -311,14 +311,12 @@ bool Compile (PDictionary plist) return false; } - var currentSDK = Sdks.GetAppleSdk (Platform); - sdkVersion = AppleSdkVersion.Parse (DefaultSdkVersion); - if (!currentSDK.SdkIsInstalled (sdkVersion, SdkIsSimulator)) { + if (!CurrentSdk.SdkIsInstalled (sdkVersion, SdkIsSimulator)) { Log.LogError (null, null, null, null, 0, 0, 0, 0, MSBStrings.E0013, Platform, sdkVersion); return false; } - SetXcodeValues (plist, currentSDK); + SetXcodeValues (plist, CurrentSdk); } switch (Platform) { @@ -426,7 +424,7 @@ void Validation (PDictionary plist) GetMinimumOSVersion (plist, out var minimumOSVersion); if (minimumOSVersion < new Version (11, 0)) { string miniOSVersion = "?"; - if (MacCatalystSupport.TryGetiOSVersion (Sdks.GetAppleSdk (Platform).GetSdkPath (SdkVersion), minimumOSVersion, out var iOSVersion, out var _)) + if (MacCatalystSupport.TryGetiOSVersion (CurrentSdk.GetSdkPath (SdkVersion), minimumOSVersion, out var iOSVersion, out var _)) miniOSVersion = iOSVersion?.ToString () ?? "?"; LogAppManifestError (MSBStrings.E7099 /* The UIDeviceFamily value '6' requires macOS 11.0. Please set the 'SupportedOSPlatformVersion' in the project file to at least 14.0 (the Mac Catalyst version equivalent of macOS 11.0). The current value is {0} (equivalent to macOS {1}). */, miniOSVersion, minimumOSVersion); } @@ -512,7 +510,7 @@ void SetXcodeValues (PDictionary plist, IAppleSdk currentSDK) SetValueIfNotNull (plist, "DTPlatformName", PlatformUtils.GetTargetPlatform (SdkPlatform, false)); SetValueIfNotNull (plist, "DTPlatformVersion", dtSettings.DTPlatformVersion); SetValueIfNotNull (plist, "DTSDKName", sdkSettings.CanonicalName); - SetValueIfNotNull (plist, "DTXcode", AppleSdkSettings.DTXcode); + SetValueIfNotNull (plist, "DTXcode", GetXcodeLocator ().DTXcode); SetValueIfNotNull (plist, "DTXcodeBuild", dtSettings.DTXcodeBuild); } diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileEntitlements.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileEntitlements.cs index 3f5ac630ef5c..3e2e85074957 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileEntitlements.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileEntitlements.cs @@ -117,7 +117,7 @@ string DefaultEntitlementsPath { return "Entitlements.plist"; } - return Path.Combine (Sdks.GetAppleSdk (TargetFrameworkMoniker).GetSdkPath (SdkVersion, false), "Entitlements.plist"); + return Path.Combine (CurrentSdk.GetSdkPath (SdkVersion, false), "Entitlements.plist"); } } diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeNativeAOTSurvivingNativeSymbols.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeNativeAOTSurvivingNativeSymbols.cs index 67eda6ed7ec0..136e6c321b8f 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeNativeAOTSurvivingNativeSymbols.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeNativeAOTSurvivingNativeSymbols.cs @@ -14,7 +14,7 @@ namespace Xamarin.MacDev.Tasks { /// Takes the list of unresolved native symbols from a NativeAOT static library and computes /// which inlined dlfcn native symbols survived trimming. The output file has the same format /// as CollectPostILTrimInformation's surviving symbols file. - /// See docs/code/native-symbols.md for an overview of native symbol handling. + /// See docs/code/native-symbols.md and docs/code/class-handles.md for an overview of native symbol handling. /// public class ComputeNativeAOTSurvivingNativeSymbols : XamarinTask { /// @@ -29,39 +29,17 @@ public class ComputeNativeAOTSurvivingNativeSymbols : XamarinTask { [Required] public string SurvivingNativeSymbolsFile { get; set; } = ""; + /// + /// Output file listing the Class.GetHandle calls that survived trimming. + /// + [Required] + public string SurvivingClassesFile { get; set; } = ""; + public override bool Execute () { - if (!File.Exists (UnresolvedSymbolsFile)) - return !Log.HasLoggedErrors; - - const string prefix = "_xamarin_Dlfcn_"; - const string suffix = "_Native"; - var survivingSymbols = new HashSet (); - - foreach (var sym in File.ReadAllLines (UnresolvedSymbolsFile)) { - if (!sym.StartsWith (prefix) || !sym.EndsWith (suffix)) - continue; - var symbolLength = sym.Length - prefix.Length - suffix.Length; - if (symbolLength <= 0) - continue; - var symbolName = sym.Substring (prefix.Length, symbolLength); - survivingSymbols.Add (symbolName); - } - - var sorted = survivingSymbols.OrderBy (s => s).ToArray (); - - if (File.Exists (SurvivingNativeSymbolsFile)) { - var existing = File.ReadAllLines (SurvivingNativeSymbolsFile); - if (existing.SequenceEqual (sorted)) - return !Log.HasLoggedErrors; - } - - var dir = Path.GetDirectoryName (SurvivingNativeSymbolsFile); - if (!string.IsNullOrEmpty (dir)) - Directory.CreateDirectory (dir); - File.WriteAllLines (SurvivingNativeSymbolsFile, sorted); - Log.LogMessage (MessageImportance.Low, "Found {0} surviving native symbols from NativeAOT", survivingSymbols.Count); - + var unresolvedSymbols = File.Exists (UnresolvedSymbolsFile) ? File.ReadAllLines (UnresolvedSymbolsFile) : []; + CollectPostILTrimInformation.WriteSymbolsToFile (this, SurvivingNativeSymbolsFile, CollectPostILTrimInformation.FilterToDlfcnSymbols (unresolvedSymbols)); + CollectPostILTrimInformation.WriteSymbolsToFile (this, SurvivingClassesFile, CollectPostILTrimInformation.FilterToClassSymbols (unresolvedSymbols)); return !Log.HasLoggedErrors; } } diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSdkLocation.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSdkLocation.cs index 1f393504e6a8..f06f132d6a7b 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSdkLocation.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSdkLocation.cs @@ -29,6 +29,7 @@ public string SdkRoot { get; set; } = ""; + // this is input too (the variable 'XcodeLocation') [Output] public new string SdkDevPath { get => base.SdkDevPath; @@ -59,12 +60,6 @@ public string XcodeVersion { #endregion Outputs - protected IAppleSdk CurrentSdk { - get { - return Sdks.GetAppleSdk (Platform); - } - } - IAppleSdkVersion GetDefaultSdkVersion () { switch (Platform) { @@ -145,33 +140,40 @@ bool ExecuteImpl () return ExecuteRemotely (); } - AppleSdkSettings.Init (); - - if (EnsureAppleSdkRoot ()) - EnsureSdkPath (); - EnsureXamarinSdkRoot (); + var isNet11OrNewer = TargetFramework.Version.Major >= 11; + var appleSdkSettings = GetXcodeLocator (initialDiscovery: true, (locator) => { + locator.SupportEnvironmentVariableLookup = !isNet11OrNewer; + locator.SupportSettingsFileLookup = !isNet11OrNewer; + }); + SetXcodeLocator (appleSdkSettings); + SdkDevPath = appleSdkSettings.DeveloperRoot; + XcodeVersion = appleSdkSettings.XcodeVersion.ToString (); + + if (appleSdkSettings.SystemHasEnvironmentVariable) { + if (isNet11OrNewer) { + Log.LogWarning (MSBStrings.W7172 /* The environment variable '{0}' is deprecated, and will be ignored. Please set use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. */, XcodeLocator.EnvironmentVariableName); + } else { + Log.LogWarning (MSBStrings.W7171 /* The environment variable '{0}' is deprecated, and will be ignored in .NET 11+. Please set use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. */, XcodeLocator.EnvironmentVariableName); + } + } + foreach (var file in appleSdkSettings.SystemExistingSettingsFiles) { + if (isNet11OrNewer) { + Log.LogWarning (MSBStrings.W7174 /* The settings file '{0}' is deprecated, and will be ignored. Please set use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. */, file); + } else { + Log.LogWarning (MSBStrings.W7173 /* The settings file '{0}' is deprecated, and will be ignored in .NET 11+. Please set use the 'DEVELOPER_DIR' environment variable or the 'XcodeLocation' MSBuild property to choose which Xcode to use. */, file); + } + } - XcodeVersion = AppleSdkSettings.XcodeVersion.ToString (); + if (Log.HasLoggedErrors) + return false; - return !Log.HasLoggedErrors; - } + Log.LogMessage (MessageImportance.Low, "DeveloperRoot: {0}", CurrentSdk.DeveloperRoot); + Log.LogMessage (MessageImportance.Low, "GetPlatformPath: {0}", CurrentSdk.GetPlatformPath (SdkIsSimulator)); - protected bool EnsureAppleSdkRoot () - { - var currentSdk = CurrentSdk; - if (!currentSdk.IsInstalled) { - Log.LogError (MSBStrings.E0044v2 /* Could not find a valid Xcode app bundle at '{0}'. Please verify that 'xcode-select -p' points to your Xcode installation. For more information see https://aka.ms/macios-missing-xcode. */, AppleSdkSettings.InvalidDeveloperRoot); - return false; - } - Log.LogMessage (MessageImportance.Low, "DeveloperRoot: {0}", currentSdk.DeveloperRoot); - Log.LogMessage (MessageImportance.Low, "GetPlatformPath: {0}", currentSdk.GetPlatformPath (SdkIsSimulator)); + EnsureSdkPath (); + EnsureXamarinSdkRoot (); - SdkDevPath = currentSdk.DeveloperRoot; - if (string.IsNullOrEmpty (SdkDevPath)) { - Log.LogError (MSBStrings.E0086 /* Could not find a valid Xcode developer path */); - return false; - } - return true; + return !Log.HasLoggedErrors; } protected string? DirExists (string checkingFor, params string [] paths) diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSigningIdentity.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSigningIdentity.cs index 224c8e37edc4..8718934d6918 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSigningIdentity.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSigningIdentity.cs @@ -29,12 +29,6 @@ public class DetectSigningIdentity : XamarinTask, ITaskCallback, ICancelableTask static readonly string [] macDirectDistributionPrefixes = { "Developer ID Application" }; static readonly string [] macDevelopmentPrefixes = { "Mac Developer", "Apple Development" }; - protected string DeveloperRoot { - get { - return Sdks.GetAppleSdk (TargetFrameworkMoniker).DeveloperRoot; - } - } - protected string [] DevelopmentPrefixes { get { switch (Platform) { @@ -583,7 +577,7 @@ bool ExecuteImpl () else if (ProvisioningProfile == AutomaticAdHocProvision) type = MobileProvisionDistributionType.AdHoc; - DetectedCodesignAllocate = Path.Combine (DeveloperRoot, "Toolchains", "XcodeDefault.xctoolchain", "usr", "bin", "codesign_allocate"); + DetectedCodesignAllocate = Path.Combine (CurrentSdk.DeveloperRoot, "Toolchains", "XcodeDefault.xctoolchain", "usr", "bin", "codesign_allocate"); DetectedDistributionType = type.ToString (); identity.BundleId = BundleIdentifier; diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/PostTrimmingProcessing.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/PostTrimmingProcessing.cs index 77705a8dd1d7..bb65800df942 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/PostTrimmingProcessing.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/PostTrimmingProcessing.cs @@ -9,13 +9,14 @@ using Microsoft.Build.Framework; using Xamarin.Bundler; +using Xamarin.Utils; #nullable enable namespace Xamarin.MacDev.Tasks { /// /// Performs post-trimming processing, generating native code only for symbols that survived trimming. - /// See docs/code/native-symbols.md for an overview of native symbol handling. + /// See docs/code/native-symbols.md and docs/code/class-handles.md for an overview of native symbol handling. /// public class PostTrimmingProcessing : XamarinTask { [Required] @@ -26,6 +27,13 @@ public class PostTrimmingProcessing : XamarinTask { public ITaskItem [] ReferenceNativeSymbol { get; set; } = []; + /// + /// Files listing calls to Class.GetHandle that survived trimming. Each file contains one symbol name per line. + /// These can come from either ILTrim (CollectPostILTrimInformation) or NativeAOT + /// (ComputeNativeAOTSurvivingNativeSymbols). + /// + public ITaskItem [] SurvivingClassesFiles { get; set; } = []; + /// /// Files listing native symbols that survived trimming. Each file contains one symbol name per line. /// These can come from either ILTrim (CollectPostILTrimInformation) or NativeAOT @@ -33,6 +41,9 @@ public class PostTrimmingProcessing : XamarinTask { /// public ITaskItem [] SurvivingNativeSymbolsFiles { get; set; } = []; + // Type map + public string TypeMapFilePath { get; set; } = ""; + /// /// Output native source files to be compiled and linked. /// @@ -71,41 +82,166 @@ HashSet IgnoredSymbols { public override bool Execute () { - var items = new List (); + var nativeSourceFiles = new List (); + + Directory.CreateDirectory (OutputDirectory); + GenerateInlinedDlfcnNativeCode (nativeSourceFiles); + GenerateInlinedClassGetHandleNativeCode (nativeSourceFiles); - GenerateInlinedDlfcnNativeCode (items); + NativeSourceFiles = nativeSourceFiles.Select (path => { + var item = new Microsoft.Build.Utilities.TaskItem (path); + item.SetMetadata ("Arch", Architecture.ToLowerInvariant ()); + return item; + }).ToArray (); - NativeSourceFiles = items.ToArray (); return !Log.HasLoggedErrors; } - void GenerateInlinedDlfcnNativeCode (List items) + static HashSet ReadUniqueLinesFromFiles (IEnumerable files) { - // Collect all surviving symbols from all input files. - var survivingSymbols = new HashSet (); - foreach (var file in SurvivingNativeSymbolsFiles) { + var lines = new HashSet (); + foreach (var file in files) { var path = file.ItemSpec; if (!File.Exists (path)) continue; - survivingSymbols.UnionWith (File.ReadAllLines (path)); + lines.UnionWith (File.ReadAllLines (path)); + } + return lines; + } + + List FilterOutIgnoredSymbols (HashSet survivingSymbols, bool filterObjectiveCClasses) + { + var rv = new HashSet (survivingSymbols); + + foreach (var rns in ReferenceNativeSymbol) { + var nativeSymbol = rns.ItemSpec; + var symbolMode = rns.GetMetadata ("SymbolMode"); + if (!string.Equals (symbolMode, "Ignore", StringComparison.OrdinalIgnoreCase)) + continue; + + var symbolType = rns.GetMetadata ("SymbolType").ToLowerInvariant (); + switch (symbolType) { + case "objectivecclass": + if (filterObjectiveCClasses && rv.Remove (nativeSymbol)) { + Log.LogMessage (MessageImportance.Low, "Ignoring Objective-C class '{0}'", nativeSymbol); + } + break; + case "function": + case "field": + if (!filterObjectiveCClasses && rv.Remove (nativeSymbol)) { + Log.LogMessage (MessageImportance.Low, "Ignoring native symbol '{0}'", nativeSymbol); + } + break; + default: + Log.LogMessage (MessageImportance.Low, "Ignoring symbol '{0}' with unknown SymbolType '{1}'", nativeSymbol, symbolType); + continue; + } + } + + rv.Remove (""); // no empty symbols + + return rv.OrderBy (v => v).ToList (); + } + + void GenerateInlinedClassGetHandleNativeCode (List items) + { + // Collect all surviving symbols from all input files. + var classes = FilterOutIgnoredSymbols (ReadUniqueLinesFromFiles (SurvivingClassesFiles), filterObjectiveCClasses: true); + + if (classes.Count == 0) { + Log.LogMessage (MessageImportance.Low, "There were no surviving Objective-C classes that require inlined Class.GetHandle native code."); + return; + } + + if (string.IsNullOrEmpty (TypeMapFilePath) || !File.Exists (TypeMapFilePath)) { + Log.LogError ("The type map file '{0}' does not exist. This file is generated by the linker's CoreTypeMapStep. Ensure that trimming ran successfully.", TypeMapFilePath ?? ""); + return; + } + + var typeMapEntries = File.ReadAllLines (TypeMapFilePath) + .Select (line => { + var parts = line.Split ('|'); + string className = ""; + string framework = ""; + string introduced = ""; + bool iswrapper = false; + bool isstubclass = false; + foreach (var part in parts) { + var kvp = part.Split (new char [] { '=' }, 2); + if (kvp.Length != 2) + continue; + var key = kvp [0].Trim (); + var value = kvp [1].Trim (); + switch (key) { + case "Class": + className = value; + break; + case "Framework": + framework = value; + break; + case "Introduced": + introduced = value; + break; + case "IsWrapper": + iswrapper = string.Equals (value, "true", StringComparison.OrdinalIgnoreCase); + break; + case "IsStubClass": + isstubclass = string.Equals (value, "true", StringComparison.OrdinalIgnoreCase); + break; + } + } + return (Class: className, Framework: framework, Introduced: introduced, IsWrapper: iswrapper, IsStubClass: isstubclass); + }) + .ToArray (); + + var typeMap = new Dictionary (); + foreach (var entry in typeMapEntries) { + if (string.IsNullOrEmpty (entry.Class)) + continue; + if (typeMap.ContainsKey (entry.Class)) { + Log.LogError ("Duplicate class '{0}' found in the type map file '{1}'.", entry.Class, TypeMapFilePath); + return; + } + typeMap [entry.Class] = entry; } - var survivingButIgnoredSymbols = survivingSymbols.Intersect (IgnoredSymbols).ToList (); - if (survivingButIgnoredSymbols.Count > 0) { - Log.LogMessage (MessageImportance.Low, "The following symbols survived trimming but are marked as ignored:"); - foreach (var symbol in survivingButIgnoredSymbols) - Log.LogMessage (MessageImportance.Low, " {0}", symbol); - survivingSymbols.ExceptWith (survivingButIgnoredSymbols); + var sb = new StringBuilder (); + sb.AppendLine ($"#include "); + sb.AppendLine ($"#include "); + foreach (var objectiveCClassName in classes) { + // We don't want to import every header under the sun to find the @interface definitions for each class, so we generate + // a forward declaration for each class. To avoid potential issues with missing classes at runtime, we mark each declaration with __attribute__((weak_import)). + // The only exception is that we need to #include Foundation, which means we can't create declarations for Foundation classes. + if (!typeMap.TryGetValue (objectiveCClassName, out var info)) { + sb.AppendLine ($"__attribute__((weak_import)) @interface {objectiveCClassName} : NSObject @end // no objc type found"); + } else if (info.IsWrapper && info.Framework == "Foundation") { + // This is a special case for wrapper classes in the Foundation framework. Since we need to #include Foundation, we can't create a forward declaration for these classes. However, since they are wrappers, we know they won't be missing at runtime, so we don't need to mark them with __attribute__((weak_import)). + sb.AppendLine ($"// The class '{objectiveCClassName}' comes from the Foundation framework, so no generated @interface declaration."); + } else { + if (info.IsStubClass) + sb.AppendLine ("__attribute__((objc_class_stub)) __attribute__((objc_subclassing_restricted))"); + sb.AppendLine ($"__attribute__((weak_import)) @interface {objectiveCClassName} : NSObject @end // is stub: {info.IsStubClass}"); + } + sb.AppendLine ($"Class xamarin_Class_GetHandle_{objectiveCClassName}_Native ();"); + sb.AppendLine ($"Class xamarin_Class_GetHandle_{objectiveCClassName}_Native () {{ return [{objectiveCClassName} class]; }}"); + sb.AppendLine (); } + var outputPath = Path.Combine (OutputDirectory, "inlined-class-gethandle.m"); + FileUtils.WriteIfDifferent (outputPath, sb.ToString (), (msg) => Log.LogMessage (MessageImportance.Low, msg)); + + items.Add (outputPath); + } + + void GenerateInlinedDlfcnNativeCode (List items) + { + var survivingSymbols = FilterOutIgnoredSymbols (ReadUniqueLinesFromFiles (SurvivingNativeSymbolsFiles), filterObjectiveCClasses: false); + if (survivingSymbols.Count == 0) { Log.LogMessage (MessageImportance.Low, "There were no surviving symbols that require inlined dlfcn native code."); return; } - Directory.CreateDirectory (OutputDirectory); - var outputPath = Path.Combine (OutputDirectory, "inlined-dlfcn.c"); - var sb = new StringBuilder (); // The generated C code uses 'extern void*' declarations and returns the address of the symbol. // This is intentional: it allows the native linker to resolve the symbol at link time, which @@ -118,17 +254,10 @@ void GenerateInlinedDlfcnNativeCode (List items) sb.AppendLine (); } - var content = sb.ToString (); - if (File.Exists (outputPath) && File.ReadAllText (outputPath) == content) { - Log.LogMessage (MessageImportance.Low, "Inlined dlfcn native code is up to date"); - } else { - File.WriteAllText (outputPath, content); - Log.LogMessage (MessageImportance.Low, "Generated inlined dlfcn native code with {0} symbols", survivingSymbols.Count); - } + var outputPath = Path.Combine (OutputDirectory, "inlined-dlfcn.c"); + FileUtils.WriteIfDifferent (outputPath, sb.ToString (), (msg) => Log.LogMessage (MessageImportance.Low, msg)); - var item = new Microsoft.Build.Utilities.TaskItem (outputPath); - item.SetMetadata ("Arch", Architecture.ToLowerInvariant ()); - items.Add (item); + items.Add (outputPath); } } } diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/ReadAppManifest.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/ReadAppManifest.cs index ed31af9848f6..6e70959e2d15 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/ReadAppManifest.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/ReadAppManifest.cs @@ -73,7 +73,7 @@ public override bool Execute () if (Platform == ApplePlatform.MacCatalyst) { // The minimum version in the Info.plist is the macOS version. However, the rest of our tooling // expects the iOS version, so expose that. - if (!MacCatalystSupport.TryGetiOSVersion (Sdks.GetAppleSdk (Platform).GetSdkPath (), MinimumOSVersion!, out var convertedVersion, out var knownMacOSVersions)) + if (!MacCatalystSupport.TryGetiOSVersion (CurrentSdk.GetSdkPath (), MinimumOSVersion!, out var convertedVersion, out var knownMacOSVersions)) Log.LogError (MSBStrings.E0187, MinimumOSVersion, string.Join (", ", knownMacOSVersions.OrderBy (v => v))); MinimumOSVersion = convertedVersion; } diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinTask.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinTask.cs index 1313a4d5e902..2ad8f996c312 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinTask.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinTask.cs @@ -35,6 +35,52 @@ public string GetSdkDevPath () return SdkDevPath; } + XcodeLocator? xcodeLocator = null; + public XcodeLocator GetXcodeLocator (bool initialDiscovery = false, Action? preprocess = null) + { + if (xcodeLocator is null) { + if (!initialDiscovery && string.IsNullOrEmpty (SdkDevPath)) { + Log.LogError (MSBStrings.E7169, /* The task '{0}' requires the property '{1}' to be set. Please file an issue at https://github.com/dotnet/macios/issues/new/choose. */ GetType ().Name, "SdkDevPath"); + } + + var xcodeLocator = new XcodeLocator (this); + preprocess?.Invoke (xcodeLocator); + if (!xcodeLocator.TryLocatingXcode (SdkDevPath)) + Log.LogError (MSBStrings.E0086 /* Could not find a valid Xcode developer path */); + this.xcodeLocator = xcodeLocator; + } + return xcodeLocator; + } + + protected void SetXcodeLocator (XcodeLocator xcodeLocator) + { + this.xcodeLocator = xcodeLocator; + } + + IAppleSdk? currentSdk; + public IAppleSdk CurrentSdk { + get { + if (currentSdk is null) { + var xcodeLocator = GetXcodeLocator (); + switch (Platform) { + case ApplePlatform.iOS: + currentSdk = new AppleIPhoneSdk (xcodeLocator.DeveloperRoot, xcodeLocator.DeveloperRootVersionPlist); + break; + case ApplePlatform.TVOS: + currentSdk = new AppleTVOSSdk (xcodeLocator.DeveloperRoot, xcodeLocator.DeveloperRootVersionPlist); + break; + case ApplePlatform.MacCatalyst: + case ApplePlatform.MacOSX: + currentSdk = new MacOSXSdk (xcodeLocator.DeveloperRoot, xcodeLocator.DeveloperRootVersionPlist); + break; + default: + throw new InvalidOperationException (string.Format (MSBStrings.InvalidPlatform, Platform)); + } + } + return currentSdk; + } + } + void VerifyTargetFrameworkMoniker () { if (!string.IsNullOrEmpty (TargetFrameworkMoniker)) diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.targets b/msbuild/Xamarin.Shared/Xamarin.Shared.targets index 2324108e27c5..8223821d1057 100644 --- a/msbuild/Xamarin.Shared/Xamarin.Shared.targets +++ b/msbuild/Xamarin.Shared/Xamarin.Shared.targets @@ -685,6 +685,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. ProjectDir="$(MSBuildProjectDirectory)" ResourcePrefix="$(_ResourcePrefix)" ResourceRules="$(_PreparedResourceRules)" + SdkDevPath="$(_SdkDevPath)" SdkIsSimulator="$(_SdkIsSimulator)" SdkVersion="$(_SdkVersion)" SupportedOSPlatformVersion="$(SupportedOSPlatformVersion)" @@ -711,6 +712,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. Condition="'$(IsMacEnabled)' == 'true' And '$(_BundleOriginalResources)' != 'true'" SessionId="$(BuildSessionId)" AppManifest="$(_TemporaryAppManifest)" + SdkDevPath="$(_SdkDevPath)" TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)" > @@ -798,6 +800,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. Entitlements="$(CodesignEntitlements)" CompiledEntitlements="$(_CompiledEntitlementsPath)" ProvisioningProfile="$(_ProvisioningProfile)" + SdkDevPath="$(_SdkDevPath)" SdkIsSimulator="$(_SdkIsSimulator)" SdkPlatform="$(_SdkPlatform)" SdkVersion="$(_SdkVersion)" @@ -2070,6 +2073,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. SdkIsSimulator="$(_SdkIsSimulator)" SdkPlatform="$(_SdkPlatform)" ProvisioningProfile="$(CodesignProvision)" + SdkDevPath="$(_SdkDevPath)" SigningKey="$(_SpecifiedCodesignKey)" DetectedCodeSigningKey="$(_CodeSigningKey)" TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)" @@ -2092,6 +2096,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. data->flags; + struct NSObjectData *data = (struct NSObjectData *) ptr; + enum NSObjectFlags flags = (enum NSObjectFlags) data->flags; bool isRegisteredToggleRef = (flags & NSObjectFlagsRegisteredToggleRef) == NSObjectFlagsRegisteredToggleRef; - id handle = info->data->handle; + id handle = data->handle; MonoToggleRefStatus res = (MonoToggleRefStatus) 0; if (isRegisteredToggleRef) { @@ -337,9 +333,9 @@ void xamarin_coreclr_reference_tracking_tracked_object_entered_finalization (void* ptr) { - struct TrackedObjectInfo *info = (struct TrackedObjectInfo *) ptr; - info->data->flags = (enum NSObjectFlags) (info->data->flags | NSObjectFlagsInFinalizerQueue); - LOG_CORECLR (stderr, "%s (%p) flags: %i\n", __func__, ptr, (int) info->data->flags); + struct NSObjectData *data = (struct NSObjectData *) ptr; + data->flags = (enum NSObjectFlags) (data->flags | NSObjectFlagsInFinalizerQueue); + LOG_CORECLR (stderr, "%s (%p) flags: %i\n", __func__, ptr, (int) data->flags); } void diff --git a/runtime/xamarin/runtime.h b/runtime/xamarin/runtime.h index fd5c697efff5..d9a8961a4598 100644 --- a/runtime/xamarin/runtime.h +++ b/runtime/xamarin/runtime.h @@ -367,10 +367,9 @@ extern xamarin_register_assemblies_callback xamarin_register_assemblies; // This has a managed equivalent in NSObject.cs struct NSObjectData { id handle; - struct objc_super* super; uint32_t /* NSObjectFlags */ flags; // if this structure ever changes, the encoding for this method will likely have to be updated in Registrar.RegistrarTypeUnsafe, currently it's: - // Signature = "^{NSObjectData=@^{objc_super}I}:", + // Signature = "^{NSObjectData=@I}:", }; #ifdef __cplusplus diff --git a/src/Foundation/NSObject2.cs b/src/Foundation/NSObject2.cs index 7f1a5adb7e8e..22498aeed364 100644 --- a/src/Foundation/NSObject2.cs +++ b/src/Foundation/NSObject2.cs @@ -119,12 +119,9 @@ internal interface INSObjectFactory { #if !COREBUILD // Allocated in native memory, so that it can be accessed from native code without having to deal with the GC. - // Also put objc_super here, because it simplifies code. // This is mirrored in runtime.h and the definition needs to be in sync. - struct NSObjectData { - // the layout here is important, the two first fields have to match the objc_super struct. + internal struct NSObjectData { public NativeHandle handle; - public NativeHandle classHandle; public NSObject.Flags flags; } @@ -137,34 +134,42 @@ struct NSObjectData { // * https://github.com/AustinWise/runtime/blob/2bd10ad43df967950657ae0ade1f899dc1b18a41/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ObjectiveCMarshal.NativeAot.cs#L15 // * https://github.com/AustinWise/runtime/blob/2bd10ad43df967950657ae0ade1f899dc1b18a41/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ObjectiveCMarshal.NativeAot.cs#L59-L71 // * https://github.com/AustinWise/runtime/blob/2bd10ad43df967950657ae0ade1f899dc1b18a41/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ObjectiveCMarshal.NativeAot.cs#L181-L185 - unsafe class NSObjectDataHandle { - NSObjectData* data; + unsafe class NSObjectDataHandle : TrackedMemory { + public NSObjectData* Data { get => (NSObjectData*) Value; } + + public NSObjectDataHandle () : base ((nuint) sizeof (NSObjectData)) + { + } + } + + class TrackedMemory { GCHandle handle; - public NSObjectData* Data { get => data; } + public IntPtr Value { get; private set; } - public NSObjectDataHandle () + public unsafe TrackedMemory (nuint size) { - data = Runtime.AllocZeroed (); + Value = (IntPtr) NativeMemory.AllocZeroed (size); } - public void CreateHandle (NSObject obj) + public unsafe void CreateHandle (NSObject trackedObject) { - handle = GCHandle.Alloc (obj, GCHandleType.WeakTrackResurrection); + handle = GCHandle.Alloc (trackedObject, GCHandleType.WeakTrackResurrection); } - ~NSObjectDataHandle () + ~TrackedMemory () { var handleAllocated = handle.IsAllocated; - if (handleAllocated && handle.Target is not null) { // The NSObject instance isn't gone yet, we have to try again later. GC.ReRegisterForFinalize (this); return; } - NativeMemory.Free (data); - data = null; + unsafe { + NativeMemory.Free ((void*) Value); + } + Value = IntPtr.Zero; if (handleAllocated) handle.Free (); @@ -208,6 +213,10 @@ public partial class NSObject : INativeObject // having to attach those threads to to the managed runtime. IntPtr /* unsafe NSObjectData* */ __data; // Read directly from several places in the runtime +#pragma warning disable CS8618 // "Non-nullable field '...' must contain a non-null value when exiting constructor.": this field is always non-null, because NSObject.Initialize is called before anything else is done. + static ConditionalWeakTable super_map; +#pragma warning restore CS8618 + unsafe NativeHandle handle { get => GetData ()->handle; set => GetData ()->handle = value; @@ -219,18 +228,24 @@ unsafe NativeHandle handle { if (data != IntPtr.Zero) return (NSObjectData*) data; - var data_handle = new NSObjectDataHandle (); - var existing_data = Interlocked.CompareExchange (ref __data, (IntPtr) data_handle.Data, IntPtr.Zero); - if (existing_data != IntPtr.Zero) { - // return the existing data, the GC will collect the other one we just created - return (NSObjectData*) existing_data; + if (Runtime.IsCoreCLR) { + data = (IntPtr) Runtime.GetTaggedMemory (this); + __data = data; // Runtime.GetTaggedMemory will always return the same pointer for the same object, so no synchronization is needed here (redundant writes are benign). + return (NSObjectData*) data; + } else { + var data_handle = new NSObjectDataHandle (); + var existing_data = Interlocked.CompareExchange (ref __data, (IntPtr) data_handle.Data, IntPtr.Zero); + if (existing_data != IntPtr.Zero) { + // return the existing data, the GC will collect the other one we just created + return (NSObjectData*) existing_data; + } + // tell the data handle we just created to track us + data_handle.CreateHandle (this); + // make sure the data isn't freed before this NSObject is collected, but also + // that it is freed after this NSObject is collected. + data_table.Add (this, data_handle); + return data_handle.Data; } - // tell the data handle we just created to track us - data_handle.CreateHandle (this); - // make sure the data isn't freed before this NSObject is collected, but also - // that it is freed after this NSObject is collected. - data_table.Add (this, data_handle); - return data_handle.Data; } unsafe Flags flags { @@ -388,17 +403,29 @@ internal static IntPtr CreateNSObject (IntPtr type_gchandle, IntPtr handle, Flag } } +#if !XAMCORE_5_0 unsafe NativeHandle GetSuper () { - var data = GetData (); - if (data->classHandle == NativeHandle.Zero) - data->classHandle = ClassHandle; - return (IntPtr) (&data->handle); + var memory = super_map.GetValue (this, (obj) => { + unsafe { + var memory = new TrackedMemory ((nuint) sizeof (objc_super)); + memory.CreateHandle (obj); + return memory; + } + }); + objc_super* sup = (objc_super*) memory.Value; + if (sup->ClassHandle == NativeHandle.Zero) + sup->ClassHandle = ClassHandle; + sup->Handle = handle; + return memory.Value; } +#endif // !XAMCORE_5_0 internal static NativeHandle Initialize () { - data_table = new ConditionalWeakTable (); + if (!Runtime.IsCoreCLR) + data_table = new ConditionalWeakTable (); + super_map = new ConditionalWeakTable (); return class_ptr; } @@ -722,16 +749,35 @@ public NSObject DangerousAutorelease () return this; } +#if !XAMCORE_5_0 /// Handle used to represent the methods in the base class for this . /// An opaque pointer, represents an Objective-C objc_super object pointing to our base class. /// - /// This property is used to access members of a base class. - /// This is typically used when you call any of the Messaging - /// methods to invoke methods that were implemented in your base - /// class, instead of invoking the implementation in the current - /// class. + /// + /// This property is used to access members of a base class. + /// This is typically used when you call any of the Messaging + /// methods to invoke methods that were implemented in your base + /// class, instead of invoking the implementation in the current + /// class. + /// + /// + /// This property is obsolete; use the struct instead: + /// + /// + /// + /// /// [EditorBrowsable (EditorBrowsableState.Never)] +#if NET11_0_OR_GREATER + [Obsolete ("Use 'ObjCSuper' instead.")] +#endif public NativeHandle SuperHandle { get { if (handle == IntPtr.Zero) @@ -740,6 +786,7 @@ public NativeHandle SuperHandle { return GetSuper (); } } +#endif // !XAMCORE_5_0 /// Handle (pointer) to the unmanaged object representation. /// A pointer. diff --git a/src/Foundation/NSUrlSessionHandler.cs b/src/Foundation/NSUrlSessionHandler.cs index 2c0af8202220..fc35793204e2 100644 --- a/src/Foundation/NSUrlSessionHandler.cs +++ b/src/Foundation/NSUrlSessionHandler.cs @@ -1175,15 +1175,19 @@ static bool TryGetAuthenticationType (NSUrlProtectionSpace protectionSpace, [Not authenticationType = "basic"; } else if (protectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodHTTPDigest) { authenticationType = "digest"; - } else if (protectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodNegotiate || - protectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodHTMLForm) { - // Want to reject this authentication type to allow the next authentication method in the request to - // be used. - authenticationType = RejectProtectionSpaceAuthType; - } else { - // ServerTrust, ClientCertificate or Default. + } else if (protectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodServerTrust || + protectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodClientCertificate) { + // ServerTrust and ClientCertificate are handled earlier in DidReceiveChallengeImpl, + // so we should not reach here for these types. Return false just in case. authenticationType = null; return false; + } else { + // For any other authentication method (Negotiate, HTMLForm, Bearer, etc.), + // reject this protection space to allow the next authentication method in the + // request to be tried. This is important when the server advertises multiple + // WWW-Authenticate challenges (e.g. Bearer before Basic) - rejecting unsupported + // methods allows fallback to one we can handle. + authenticationType = RejectProtectionSpaceAuthType; } return true; } diff --git a/src/ObjCRuntime/Registrar.cs b/src/ObjCRuntime/Registrar.cs index 173bf5645c4d..3b7c402bd3cf 100644 --- a/src/ObjCRuntime/Registrar.cs +++ b/src/ObjCRuntime/Registrar.cs @@ -1119,7 +1119,7 @@ protected virtual void OnRegisterCategory (ObjCType type, [NotNullIfNotNull (nam protected abstract ConnectAttribute? GetConnectAttribute (TProperty property); // Return null if no attribute is found. Do not consider inherited properties. public abstract ProtocolAttribute? GetProtocolAttribute (TType type); // Return null if no attribute is found. Do not consider base types. protected abstract IEnumerable GetProtocolMemberAttributes (TType type); // Return null if no attributes found. Do not consider base types. - protected virtual Version? GetSdkIntroducedVersion (TType obj, out string? message) { message = null; return null; } // returns the sdk version when the type was introduced for the current platform (null if all supported versions) + public virtual Version? GetSdkIntroducedVersion (TType obj, out string? message) { message = null; return null; } // returns the sdk version when the type was introduced for the current platform (null if all supported versions) protected abstract Version GetSDKVersion (); protected abstract TType? GetProtocolAttributeWrapperType (TType type); // Return null if no attribute is found. Do not consider base types. public abstract BindAsAttribute? GetBindAsAttribute (TMethod method, int parameter_index); // If parameter_index = -1 then get the attribute for the return type. Return null if no attribute is found. Must consider base method. @@ -2125,7 +2125,7 @@ void FlattenInterfaces (TType? [] ifaces) objcType.Add (new ObjCMethod (this, objcType, null) { Selector = "xamarinGetNSObjectData", Trampoline = Trampoline.GetNSObjectData, - Signature = "^{NSObjectData=@^{objc_super}I}:", + Signature = "^{NSObjectData=@I}:", IsStatic = false, }, ref exceptions); } @@ -2639,6 +2639,26 @@ protected string ToSignature (TType type, ObjCMember member, bool forProperty = throw ErrorHelper.CreateError (4101, Errors.MT4101, GetTypeFullName (type)); } + // Gets the Objective-C name for the given type. + // Returns false if the type in question isn't exported to Objective-C, and thus doesn't have an Objective-C name. + public bool TryGetExportedTypeName (TType type, [NotNullWhen (true)] out string? name) + { + name = null; + + var registerAttribute = GetRegisterAttribute (type); + if (registerAttribute is null) + return false; + + if (!registerAttribute.IsWrapper) + return false; + + if (HasProtocolAttribute (type)) + return false; + + name = GetExportedTypeName (type, registerAttribute); + return true; + } + public string GetExportedTypeName (TType type, RegisterAttribute? register_attribute) { string? name = null; diff --git a/src/ObjCRuntime/Runtime.CoreCLR.cs b/src/ObjCRuntime/Runtime.CoreCLR.cs index fff4e97daf4f..c4cf3636de4b 100644 --- a/src/ObjCRuntime/Runtime.CoreCLR.cs +++ b/src/ObjCRuntime/Runtime.CoreCLR.cs @@ -205,28 +205,35 @@ static void RaiseAppDomainUnhandledExceptionEvent (IntPtr gchandle) ExceptionHandling.RaiseAppDomainUnhandledExceptionEvent (exception); } - // Size: 2 pointers - internal struct TrackedObjectInfo { - public unsafe NSObjectData* Data; - } - [SupportedOSPlatform ("macos")] internal static GCHandle CreateTrackingGCHandle (NSObject obj, IntPtr handle) { var gchandle = ObjectiveCMarshal.CreateReferenceTrackingHandle (obj, out var info); unsafe { - TrackedObjectInfo* tracked_info; fixed (void* ptr = info) - tracked_info = (TrackedObjectInfo*) ptr; - tracked_info->Data = obj.GetData (); - - log_coreclr ($"GetOrCreateTrackingGCHandle ({obj.GetType ().FullName}, 0x{handle.ToString ("x")}) => Info=0x{((IntPtr) tracked_info).ToString ("x")} Data=0x{(IntPtr) tracked_info->Data:x} Created new"); + log_coreclr ($"GetOrCreateTrackingGCHandle ({obj.GetType ().FullName}, 0x{handle.ToString ("x")}) => 0x{((IntPtr) ptr).ToString ("x")} Created new"); } return gchandle; } + internal unsafe static void* GetTaggedMemory (NSObject obj) + { + // If https://github.com/dotnet/runtime/issues/128476 is accepted and implemented, + // can just call that new API instead of calling ObjectiveCMarshal.CreateReferenceTrackingHandle and + // freeing the returned handle. + + var gchandle = ObjectiveCMarshal.CreateReferenceTrackingHandle (obj, out var info); + // We only care about the tagged memory ('info'), so just free the GCHandle. + // We might want to request an API to just get the tagged memory at some point. + gchandle.Free (); + // The tagged memory pointer is guaranteed to be the same for every call to ObjectiveCMarshal.CreateReferenceTrackingHandle, + // and it will automatically be freed once the 'obj' is freed by the GC (in particular _once the instance is freed_, + // not _once the instance is collectible_, which is a very important distinction for us). + return Unsafe.AsPointer (ref info.GetPinnableReference ()); + } + // See "Toggle-ref support for CoreCLR" in coreclr-bridge.m for more information. internal static void RegisterToggleReferenceCoreCLR (NSObject obj, IntPtr handle, bool isCustomType) { diff --git a/src/coreml.cs b/src/coreml.cs index d22ce5c74d6b..3e643e9dc127 100644 --- a/src/coreml.cs +++ b/src/coreml.cs @@ -1543,9 +1543,9 @@ interface MLWritable { } #if !XAMCORE_5_0 - [Deprecated (PlatformName.MacOSX, 13, 3, message: "Use Background Assets or 'NSUrlSession' instead.")] - [Deprecated (PlatformName.MacCatalyst, 16, 4, message: "Use Background Assets or 'NSUrlSession' instead.")] - [Deprecated (PlatformName.iOS, 16, 4, message: "Use Background Assets or 'NSUrlSession' instead.")] + [Obsoleted (PlatformName.MacOSX, 13, 3, message: "Use Background Assets or 'NSUrlSession' instead.")] + [Obsoleted (PlatformName.MacCatalyst, 16, 4, message: "Use Background Assets or 'NSUrlSession' instead.")] + [Obsoleted (PlatformName.iOS, 16, 4, message: "Use Background Assets or 'NSUrlSession' instead.")] [iOS (14, 0)] [MacCatalyst (14, 0)] [NoTV] @@ -1575,9 +1575,9 @@ interface MLModelCollection { #endif // !XAMCORE_5_0 #if !XAMCORE_5_0 - [Deprecated (PlatformName.MacOSX, 13, 3, message: "Use Background Assets or 'NSUrlSession' instead.")] - [Deprecated (PlatformName.MacCatalyst, 16, 4, message: "Use Background Assets or 'NSUrlSession' instead.")] - [Deprecated (PlatformName.iOS, 16, 4, message: "Use Background Assets or 'NSUrlSession' instead.")] + [Obsoleted (PlatformName.MacOSX, 13, 3, message: "Use Background Assets or 'NSUrlSession' instead.")] + [Obsoleted (PlatformName.MacCatalyst, 16, 4, message: "Use Background Assets or 'NSUrlSession' instead.")] + [Obsoleted (PlatformName.iOS, 16, 4, message: "Use Background Assets or 'NSUrlSession' instead.")] [iOS (14, 0)] [MacCatalyst (14, 0)] [NoTV] diff --git a/tests/BundledResources/ResourcesTest.cs b/tests/BundledResources/ResourcesTest.cs index e22cdc7ec85e..573102ee7133 100644 --- a/tests/BundledResources/ResourcesTest.cs +++ b/tests/BundledResources/ResourcesTest.cs @@ -22,9 +22,9 @@ public void Bundled () // files are extracted (by MonoDevelop) so we can see them in the file system // that's true for simulator or devices and whatever the linker settings are var dir = NSBundle.MainBundle.ResourcePath!; - Assert.True (File.Exists (Path.Combine (dir, "basn3p08.png")), "file-basn3p08.png"); - Assert.True (File.Exists (Path.Combine (dir, "basn3p08_with_loc.png")), "file-basn3p08_with_loc.png"); - Assert.True (File.Exists (Path.Combine (dir, "xamvideotest.mp4")), "xamvideotest.mp4"); + Assert.That (File.Exists (Path.Combine (dir, "basn3p08.png")), Is.True, "file-basn3p08.png"); + Assert.That (File.Exists (Path.Combine (dir, "basn3p08_with_loc.png")), Is.True, "file-basn3p08_with_loc.png"); + Assert.That (File.Exists (Path.Combine (dir, "xamvideotest.mp4")), Is.True, "xamvideotest.mp4"); // resources are removed by the linker or an extra step (e.g. "link sdk" or "don't link") but that // extra step is done only on device (to keep the simulator builds as fast as possible) diff --git a/tests/EmbeddedResources/ResourcesTest.cs b/tests/EmbeddedResources/ResourcesTest.cs index 04f35a6856e8..e8c83f5d9b08 100644 --- a/tests/EmbeddedResources/ResourcesTest.cs +++ b/tests/EmbeddedResources/ResourcesTest.cs @@ -23,13 +23,13 @@ public class ResourcesTest { public void Embedded () { var manager = new ResourceManager ("EmbeddedResources.Welcome", typeof (ResourcesTest).Assembly); - Assert.AreEqual ("Welcome", manager.GetString ("String1", new CultureInfo ("en")), "en"); - Assert.AreEqual ("G'day", manager.GetString ("String1", new CultureInfo ("en-AU")), "en-AU"); - Assert.AreEqual ("Willkommen", manager.GetString ("String1", new CultureInfo ("de")), "de"); - Assert.AreEqual ("Willkommen", manager.GetString ("String1", new CultureInfo ("de-DE")), "de-DE"); - Assert.AreEqual ("Bienvenido", manager.GetString ("String1", new CultureInfo ("es")), "es"); - Assert.AreEqual ("Bienvenido", manager.GetString ("String1", new CultureInfo ("es-AR")), "es-AR"); - Assert.AreEqual ("Bienvenido", manager.GetString ("String1", new CultureInfo ("es-ES")), "es-ES"); + Assert.That (manager.GetString ("String1", new CultureInfo ("en")), Is.EqualTo ("Welcome"), "en"); + Assert.That (manager.GetString ("String1", new CultureInfo ("en-AU")), Is.EqualTo ("G'day"), "en-AU"); + Assert.That (manager.GetString ("String1", new CultureInfo ("de")), Is.EqualTo ("Willkommen"), "de"); + Assert.That (manager.GetString ("String1", new CultureInfo ("de-DE")), Is.EqualTo ("Willkommen"), "de-DE"); + Assert.That (manager.GetString ("String1", new CultureInfo ("es")), Is.EqualTo ("Bienvenido"), "es"); + Assert.That (manager.GetString ("String1", new CultureInfo ("es-AR")), Is.EqualTo ("Bienvenido"), "es-AR"); + Assert.That (manager.GetString ("String1", new CultureInfo ("es-ES")), Is.EqualTo ("Bienvenido"), "es-ES"); } } } diff --git a/tests/bindings-test/ProtocolTest.cs b/tests/bindings-test/ProtocolTest.cs index b9d2ae0495e9..f94355ccc85f 100644 --- a/tests/bindings-test/ProtocolTest.cs +++ b/tests/bindings-test/ProtocolTest.cs @@ -46,23 +46,23 @@ public void Constructors () using var dateNow = (NSDate) DateTime.Now; using (var obj = IConstructorProtocol.CreateInstance ("Hello world")!) { - Assert.AreEqual ("Hello world", obj.StringValue, "A StringValue"); - Assert.IsNull (obj.DateValue, "A DateValue"); + Assert.That (obj.StringValue, Is.EqualTo ("Hello world"), "A StringValue"); + Assert.That (obj.DateValue, Is.Null, "A DateValue"); } using (var obj = IConstructorProtocol.CreateInstance (dateNow)!) { - Assert.IsNull (obj.StringValue, "B StringValue"); - Assert.AreEqual (dateNow, obj.DateValue, "B DateValue"); + Assert.That (obj.StringValue, Is.Null, "B StringValue"); + Assert.That (obj.DateValue, Is.EqualTo (dateNow), "B DateValue"); } using (var obj = IConstructorProtocol.CreateInstance ("Hello Subclassed")!) { - Assert.AreEqual ("Hello Subclassed", obj.StringValue, "C1 StringValue"); - Assert.IsNull (obj.DateValue, "C1 DateValue"); + Assert.That (obj.StringValue, Is.EqualTo ("Hello Subclassed"), "C1 StringValue"); + Assert.That (obj.DateValue, Is.Null, "C1 DateValue"); } using (var obj = IConstructorProtocol.CreateInstance (dateNow)!) { - Assert.IsNull (obj.StringValue, "C2 StringValue"); - Assert.AreEqual (dateNow, obj.DateValue, "C2 DateValue"); + Assert.That (obj.StringValue, Is.Null, "C2 StringValue"); + Assert.That (obj.DateValue, Is.EqualTo (dateNow), "C2 DateValue"); } if (global::XamarinTests.ObjCRuntime.Registrar.IsDynamicRegistrar) { @@ -71,8 +71,8 @@ public void Constructors () }, "D1 Exception"); } else { using (var obj = IConstructorProtocol.CreateInstance ("Hello Subclassed 2")!) { - Assert.AreEqual ("Managed interceptor! Hello Subclassed 2", obj.StringValue, "D1 StringValue"); - Assert.IsNull (obj.DateValue, "D1 DateValue"); + Assert.That (obj.StringValue, Is.EqualTo ("Managed interceptor! Hello Subclassed 2"), "D1 StringValue"); + Assert.That (obj.DateValue, Is.Null, "D1 DateValue"); } } @@ -82,8 +82,8 @@ public void Constructors () }, "D2 Exception"); } else { using (var obj = IConstructorProtocol.CreateInstance (dateNow)!) { - Assert.IsNull (obj.StringValue, "D2 StringValue"); - Assert.AreEqual (dateNow.AddSeconds (42), obj.DateValue, "D2 DateValue"); + Assert.That (obj.StringValue, Is.Null, "D2 StringValue"); + Assert.That (obj.DateValue, Is.EqualTo (dateNow.AddSeconds (42)), "D2 DateValue"); } } } @@ -118,27 +118,27 @@ public void OnlyProtocol () // the interface must be created var IP1 = bindingAssembly.GetType ("Bindings.Test.Protocol.IP1")!; - Assert.IsNotNull (IP1, "IP1"); + Assert.That (IP1, Is.Not.Null, "IP1"); // with a [Protocol] attribute var IP1Attributes = IP1.GetCustomAttributes (typeof (ProtocolAttribute), false); if (HasProtocolAttributes) { - Assert.AreEqual (1, IP1Attributes.Length, "[Protocol] IP1"); + Assert.That (IP1Attributes.Length, Is.EqualTo (1), "[Protocol] IP1"); var IP1Protocol = (ProtocolAttribute) IP1Attributes [0]; - Assert.AreEqual ("P1", IP1Protocol.Name, "Name"); + Assert.That (IP1Protocol.Name, Is.EqualTo ("P1"), "Name"); // and a wrapper type var wrapperType = bindingAssembly.GetType ("Bindings.Test.Protocol.P1Wrapper"); - Assert.IsNotNull (wrapperType, "P1_Wrapper"); - Assert.AreEqual (wrapperType, IP1Protocol.WrapperType, "WrapperType"); + Assert.That (wrapperType, Is.Not.Null, "P1_Wrapper"); + Assert.That (IP1Protocol.WrapperType, Is.EqualTo (wrapperType), "WrapperType"); } else { - Assert.AreEqual (0, IP1Attributes.Length, "[Protocol] IP1"); + Assert.That (IP1Attributes.Length, Is.EqualTo (0), "[Protocol] IP1"); // and a wrapper type var wrapperType = bindingAssembly.GetType ("Bindings.Test.Protocol.P1Wrapper"); - Assert.IsNotNull (wrapperType, "P1_Wrapper"); + Assert.That (wrapperType, Is.Not.Null, "P1_Wrapper"); } // but not the model - Assert.IsNull (bindingAssembly.GetType ("Bindings.Test.Protocol.P1"), "P1"); + Assert.That (bindingAssembly.GetType ("Bindings.Test.Protocol.P1"), Is.Null, "P1"); } [Test] @@ -150,32 +150,32 @@ public void ProtocolWithBaseType () // the interface must be created var IP2 = bindingAssembly.GetType ("Bindings.Test.Protocol.IP2")!; - Assert.IsNotNull (IP2, "IP2"); + Assert.That (IP2, Is.Not.Null, "IP2"); // with a [Protocol] attribute var IP2Attributes = IP2.GetCustomAttributes (typeof (ProtocolAttribute), false); if (HasProtocolAttributes) { - Assert.AreEqual (1, IP2Attributes.Length, "[Protocol] IP2"); + Assert.That (IP2Attributes.Length, Is.EqualTo (1), "[Protocol] IP2"); var IP2Protocol = (ProtocolAttribute) IP2Attributes [0]; - Assert.AreEqual ("P2", IP2Protocol.Name, "Name"); + Assert.That (IP2Protocol.Name, Is.EqualTo ("P2"), "Name"); // and a wrapper type var wrapperType = bindingAssembly.GetType ("Bindings.Test.Protocol.P2Wrapper"); - Assert.IsNotNull (wrapperType, "P2_Wrapper"); - Assert.AreEqual (wrapperType, IP2Protocol.WrapperType, "WrapperType"); + Assert.That (wrapperType, Is.Not.Null, "P2_Wrapper"); + Assert.That (IP2Protocol.WrapperType, Is.EqualTo (wrapperType), "WrapperType"); } else { - Assert.AreEqual (0, IP2Attributes.Length, "[Protocol] IP2"); + Assert.That (IP2Attributes.Length, Is.EqualTo (0), "[Protocol] IP2"); // and a wrapper type var wrapperType = bindingAssembly.GetType ("Bindings.Test.Protocol.P2Wrapper"); - Assert.IsNotNull (wrapperType, "P2_Wrapper"); + Assert.That (wrapperType, Is.Not.Null, "P2_Wrapper"); } // and a model-like class var model = bindingAssembly.GetType ("Bindings.Test.Protocol.P2")!; - Assert.IsNotNull (model, "P2"); + Assert.That (model, Is.Not.Null, "P2"); // but without the [Model] attribute - Assert.False (model.IsDefined (typeof (ModelAttribute), false), "model"); + Assert.That (model.IsDefined (typeof (ModelAttribute), false), Is.False, "model"); } [Test] @@ -187,32 +187,32 @@ public void ProtocolWithBaseTypeAndModel () // the interface must be created var IP3 = bindingAssembly.GetType ("Bindings.Test.Protocol.IP3")!; - Assert.IsNotNull (IP3, "IP3"); + Assert.That (IP3, Is.Not.Null, "IP3"); // with a [Protocol] attribute var IP3Attributes = IP3.GetCustomAttributes (typeof (ProtocolAttribute), false); if (HasProtocolAttributes) { - Assert.AreEqual (1, IP3Attributes.Length, "[Protocol] IP3"); + Assert.That (IP3Attributes.Length, Is.EqualTo (1), "[Protocol] IP3"); var IP3Protocol = (ProtocolAttribute) IP3Attributes [0]; - Assert.AreEqual ("P3", IP3Protocol.Name, "Name"); + Assert.That (IP3Protocol.Name, Is.EqualTo ("P3"), "Name"); // and a wrapper type var wrapperType = bindingAssembly.GetType ("Bindings.Test.Protocol.P3Wrapper"); - Assert.IsNotNull (wrapperType, "P3_Wrapper"); - Assert.AreEqual (wrapperType, IP3Protocol.WrapperType, "WrapperType"); + Assert.That (wrapperType, Is.Not.Null, "P3_Wrapper"); + Assert.That (IP3Protocol.WrapperType, Is.EqualTo (wrapperType), "WrapperType"); } else { - Assert.AreEqual (0, IP3Attributes.Length, "[Protocol] IP3"); + Assert.That (IP3Attributes.Length, Is.EqualTo (0), "[Protocol] IP3"); // and a wrapper type var wrapperType = bindingAssembly.GetType ("Bindings.Test.Protocol.P3Wrapper"); - Assert.IsNotNull (wrapperType, "P3_Wrapper"); + Assert.That (wrapperType, Is.Not.Null, "P3_Wrapper"); } // and a model class var model = bindingAssembly.GetType ("Bindings.Test.Protocol.P3")!; - Assert.IsNotNull (model, "P3"); + Assert.That (model, Is.Not.Null, "P3"); // with a [Model] attribute - Assert.True (model.IsDefined (typeof (ModelAttribute), false), "model"); + Assert.That (model.IsDefined (typeof (ModelAttribute), false), Is.True, "model"); } class MembersImplementation : NSObject, Bindings.Test.Protocol.IMemberAttributes { @@ -241,14 +241,14 @@ void CleanupSignatures (objc_method_description [] methods) public void ProtocolMembers () { IntPtr protocol = objc_getProtocol ("MemberAttributes"); - Assert.AreNotEqual (IntPtr.Zero, protocol, "a"); + Assert.That (protocol, Is.Not.EqualTo (IntPtr.Zero), "a"); objc_method_description [] methods; // Required instance methods methods = protocol_copyMethodDescriptionList (protocol, true, true); CleanupSignatures (methods); - Assert.AreEqual (4, methods.Length, "Required Instance Methods: Count"); + Assert.That (methods.Length, Is.EqualTo (4), "Required Instance Methods: Count"); AssertContains (methods, new objc_method_description ("requiredInstanceMethod", "v@:"), "Required Instance Methods: requiredInstanceMethod"); AssertContains (methods, new objc_method_description ("requiredInstanceProperty", "@@:"), "Required Instance Methods: requiredInstanceProperty"); AssertContains (methods, new objc_method_description ("setRequiredInstanceProperty:", "v@:@"), "Required Instance Methods: setRequiredInstanceProperty"); @@ -257,7 +257,7 @@ public void ProtocolMembers () // Required static methods methods = protocol_copyMethodDescriptionList (protocol, true, false); CleanupSignatures (methods); - Assert.AreEqual (3, methods.Length, "Required Static Methods: Count"); + Assert.That (methods.Length, Is.EqualTo (3), "Required Static Methods: Count"); AssertContains (methods, new objc_method_description ("requiredStaticMethod", "v@:"), "Required Static Methods: requiredStaticMethod"); AssertContains (methods, new objc_method_description ("setRequiredStaticProperty:", "v@:@"), "Required Static Methods: setRequiredStaticProperty:"); AssertContains (methods, new objc_method_description ("requiredStaticProperty", "@@:"), "Required Static Methods: requiredStaticProperty"); @@ -265,7 +265,7 @@ public void ProtocolMembers () // Optional instance methods methods = protocol_copyMethodDescriptionList (protocol, false, true); CleanupSignatures (methods); - Assert.AreEqual (19, methods.Length, "Optional Instance Methods: Count"); + Assert.That (methods.Length, Is.EqualTo (19), "Optional Instance Methods: Count"); AssertContains (methods, new objc_method_description ("variadicMethod:", "v@:^v"), "Optional Instance Methods: variadicMethod:"); AssertContains (methods, new objc_method_description ("methodWithReturnType", "@@:"), "Optional Instance Methods: methodWithReturnType"); AssertContains (methods, new objc_method_description ("methodWithParameter:", "v@:i"), "Optional Instance Methods: methodWithParameter:"); @@ -289,7 +289,7 @@ public void ProtocolMembers () // Optional static methods methods = protocol_copyMethodDescriptionList (protocol, false, false); CleanupSignatures (methods); - Assert.AreEqual (3, methods.Length, "Optional Static Methods: Count"); + Assert.That (methods.Length, Is.EqualTo (3), "Optional Static Methods: Count"); AssertContains (methods, new objc_method_description ("optionalStaticMethod", "v@:"), "Optional Static Methods: optionalStaticMethod"); AssertContains (methods, new objc_method_description ("optionalStaticProperty", "@@:"), "Optional Static Methods: optionalStaticProperty"); AssertContains (methods, new objc_method_description ("setOptionalStaticProperty:", "v@:@"), "Optional Static Methods: setOptionalStaticProperty:"); @@ -301,9 +301,9 @@ public void ProtocolMembers () // see file objc4-647/runtime/objc-runtime-old.mm in Apple's open source code), // so we need to verify differently for the dynamic registrar. if (XamarinTests.ObjCRuntime.Registrar.IsStaticRegistrar) { - Assert.AreEqual (9, properties.Length, "Properties: Count"); + Assert.That (properties.Length, Is.EqualTo (9), "Properties: Count"); } else { - Assert.AreEqual (2, properties.Length, "Properties: Count"); + Assert.That (properties.Length, Is.EqualTo (2), "Properties: Count"); } AssertContains (properties, new objc_property ("requiredInstanceProperty", "T@\"NSString\",N", new objc_property_attribute [] { diff --git a/tests/bindings-test/RegistrarBindingTest.cs b/tests/bindings-test/RegistrarBindingTest.cs index 93bba2d9c9e2..fb3cf6821c83 100644 --- a/tests/bindings-test/RegistrarBindingTest.cs +++ b/tests/bindings-test/RegistrarBindingTest.cs @@ -57,7 +57,7 @@ public static void OptionalStaticCallback (Action completionHandler) public Action RequiredReturnValue () { return new Action ((v) => { - Assert.AreEqual (42, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (42), "RequiredReturnValue"); }); } @@ -65,7 +65,7 @@ public Action RequiredReturnValue () public Action OptionalReturnValue () { return new Action ((v) => { - Assert.AreEqual (42, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (42), "RequiredReturnValue"); }); } @@ -73,7 +73,7 @@ public Action OptionalReturnValue () public static Action RequiredStaticReturnValue () { return new Action ((v) => { - Assert.AreEqual (42, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (42), "RequiredReturnValue"); }); } @@ -81,7 +81,7 @@ public static Action RequiredStaticReturnValue () public static Action OptionalStaticReturnValue () { return new Action ((v) => { - Assert.AreEqual (42, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (42), "RequiredReturnValue"); }); } } @@ -99,10 +99,10 @@ public void DerivedClassBlockCallback () ObjCBlockTester.CallOptionalStaticCallback (); DerivedBlockCallbackClass.Answer = 2; - Assert.IsFalse (obj.InvokeNullableCallbackNatively (null), "NullableCallback A rv"); + Assert.That (obj.InvokeNullableCallbackNatively (null), Is.False, "NullableCallback A rv"); int nullableResult = -1; - Assert.IsTrue (obj.InvokeNullableCallbackNatively ((v) => nullableResult = v), "NullableCallback B rv"); - Assert.AreEqual (24, nullableResult, "NullableCallback result"); + Assert.That (obj.InvokeNullableCallbackNatively ((v) => nullableResult = v), Is.True, "NullableCallback B rv"); + Assert.That (nullableResult, Is.EqualTo (24), "NullableCallback result"); } } @@ -141,7 +141,7 @@ public static void OptionalStaticCallback (Action completionHandler) public override Action RequiredReturnValue () { return new Action ((v) => { - Assert.AreEqual (Answer, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (Answer), "RequiredReturnValue"); }); } @@ -150,7 +150,7 @@ public Action OptionalReturnValue () { return new Action ((v) => { Console.WriteLine ("OptionalReturnValue"); - Assert.AreEqual (Answer, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (Answer), "RequiredReturnValue"); }); } @@ -158,7 +158,7 @@ public Action OptionalReturnValue () public static Action RequiredStaticReturnValue () { return new Action ((v) => { - Assert.AreEqual (Answer, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (Answer), "RequiredReturnValue"); }); } @@ -167,7 +167,7 @@ public static Action OptionalStaticReturnValue () { return new Action ((v) => { Console.WriteLine ("OptionalStaticReturnValue"); - Assert.AreEqual (Answer, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (Answer), "RequiredReturnValue"); }); } } @@ -201,7 +201,7 @@ public static void OptionalRequiredCallback (Action completionHandler) Action IObjCProtocolBlockTest.RequiredReturnValue () { return new Action ((v) => { - Assert.AreEqual (42, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (42), "RequiredReturnValue"); }); } @@ -209,7 +209,7 @@ Action IObjCProtocolBlockTest.RequiredReturnValue () public Action OptionalReturnValue () { return new Action ((v) => { - Assert.AreEqual (42, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (42), "RequiredReturnValue"); }); } @@ -217,7 +217,7 @@ public Action OptionalReturnValue () public static Action RequiredStaticReturnValue () { return new Action ((v) => { - Assert.AreEqual (42, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (42), "RequiredReturnValue"); }); } @@ -225,7 +225,7 @@ public static Action RequiredStaticReturnValue () public static Action OptionalStaticReturnValue () { return new Action ((v) => { - Assert.AreEqual (42, v, "RequiredReturnValue"); + Assert.That (v, Is.EqualTo (42), "RequiredReturnValue"); }); } } @@ -311,7 +311,7 @@ public void ProtocolWithBlockProperties (bool required, bool instance) } } ObjCBlockTester.CallProtocolWithBlockProperties (pb, required, instance); - Assert.IsTrue (callbackCalled, "Callback"); + Assert.That (callbackCalled, Is.True, "Callback"); } } @@ -338,7 +338,7 @@ public void ProtocolWithNativeBlockProperties (bool required, bool instance) PropertyBlock.MyOptionalStaticProperty! (); } } - Assert.AreEqual (calledCounter + 1, ObjCBlockTester.CalledBlockCount, "Blocks called"); + Assert.That (ObjCBlockTester.CalledBlockCount, Is.EqualTo (calledCounter + 1), "Blocks called"); } } [Test] @@ -372,7 +372,7 @@ public void LinkedAway (bool required, bool instance) if (re.Code == 8009) { Assert.That (re.Message, Does.StartWith ("Unable to locate the block to delegate conversion method for the method Xamarin.BindingTests.RegistrarBindingTest+FakePropertyBlock.set_"), re.Message, "Message"); } else { - Assert.AreEqual ("The runtime function get_block_wrapper_creator has been linked away.", re.Message, "Message"); + Assert.That (re.Message, Is.EqualTo ("The runtime function get_block_wrapper_creator has been linked away."), "Message"); } } } diff --git a/tests/bindings-test/RuntimeTest.cs b/tests/bindings-test/RuntimeTest.cs index aea647585f60..f445ec7bca9e 100644 --- a/tests/bindings-test/RuntimeTest.cs +++ b/tests/bindings-test/RuntimeTest.cs @@ -9,7 +9,7 @@ public class RuntimeTest { [Test] public void GlobalStringTest () { - Assert.AreEqual ("There's nothing cruvus here!", (string) Globals.GlobalString, "Global string"); + Assert.That ((string) Globals.GlobalString, Is.EqualTo ("There's nothing cruvus here!"), "Global string"); } [Test] @@ -95,7 +95,7 @@ public void SwiftTest () { TestRuntime.AssertXcodeVersion (13, 0); using var obj = new SwiftTestClass (); - Assert.AreEqual ("Hello from Swift", obj.SayHello (), "Hello"); + Assert.That (obj.SayHello (), Is.EqualTo ("Hello from Swift"), "Hello"); } [Test] @@ -105,18 +105,18 @@ public void SwiftTypeEncodings () using var obj = new SwiftTestClass (); - Assert.AreEqual ("42", obj.DoSomething ("42"), "DoSomething"); + Assert.That (obj.DoSomething ("42"), Is.EqualTo ("42"), "DoSomething"); string? asyncResult = null; obj.DoSomethingAsync ("dolphins", (v) => asyncResult = v); var done = TestRuntime.RunAsync (TimeSpan.FromSeconds (5), () => asyncResult is not null); - Assert.AreEqual ("dolphins", asyncResult, "DoSomethingAsync"); - Assert.IsTrue (done, "Done"); + Assert.That (asyncResult, Is.EqualTo ("dolphins"), "DoSomethingAsync"); + Assert.That (done, Is.True, "Done"); obj.DoSomethingComplexAsync ("fish", IntPtr.Zero, (v) => asyncResult = v); done = TestRuntime.RunAsync (TimeSpan.FromSeconds (5), () => asyncResult is not null); - Assert.AreEqual ("fish", asyncResult, "DoSomethingComplexAsync"); - Assert.IsTrue (done, "Done 2"); + Assert.That (asyncResult, Is.EqualTo ("fish"), "DoSomethingComplexAsync"); + Assert.That (done, Is.True, "Done 2"); } [Test] @@ -124,7 +124,7 @@ public void SwiftTestClass2 () { TestRuntime.AssertXcodeVersion (13, 0); using var obj = new SwiftTestClass2 (); - Assert.AreEqual ("Hello from Swift 2", obj.SayHello2 (), "Hello"); + Assert.That (obj.SayHello2 (), Is.EqualTo ("Hello from Swift 2"), "Hello"); } [Test] diff --git a/tests/bindings-test2/BindingTest.cs b/tests/bindings-test2/BindingTest.cs index 7da68e8bbfc5..803e3bf91624 100644 --- a/tests/bindings-test2/BindingTest.cs +++ b/tests/bindings-test2/BindingTest.cs @@ -9,8 +9,8 @@ public class BindingTest { [Test] public void Test () { - Assert.AreEqual (42, CFunctions.getIntOfChocolate (), "chocolate"); - Assert.AreEqual (42, Bindings.Test.CFunctions.theUltimateAnswer (), "theUltimateAnswer"); + Assert.That (CFunctions.getIntOfChocolate (), Is.EqualTo (42), "chocolate"); + Assert.That (Bindings.Test.CFunctions.theUltimateAnswer (), Is.EqualTo (42), "theUltimateAnswer"); } } } diff --git a/tests/common/Assert.cs b/tests/common/Assert.cs index 5f1b7bb0f344..e16866ee8362 100644 --- a/tests/common/Assert.cs +++ b/tests/common/Assert.cs @@ -92,7 +92,7 @@ protected virtual void SetUp () public static void Assert (string msg, bool condition) { - NUnit.Framework.Assert.True (condition, msg); + Assert.That (condition, Is.True, msg); } public static void AssertEquals (object a, object b) diff --git a/tests/common/AssertHelpers.cs b/tests/common/AssertHelpers.cs index cb4aba3fe4ca..4975c7d26110 100644 --- a/tests/common/AssertHelpers.cs +++ b/tests/common/AssertHelpers.cs @@ -11,7 +11,7 @@ public static void Throws (Action action, string expectedExceptionMessage, st action (); throw new AssertionException (string.Format ("Expected {0}, but no exception was thrown. {1}.", typeof (T).FullName, message)); } catch (T ex) { - Assert.AreEqual (expectedExceptionMessage, ex.Message, message); + Assert.That (ex.Message, Is.EqualTo (expectedExceptionMessage), message); } } diff --git a/tests/common/BinLog.cs b/tests/common/BinLog.cs index f02f5123bfec..e8afbc729d96 100644 --- a/tests/common/BinLog.cs +++ b/tests/common/BinLog.cs @@ -210,6 +210,9 @@ public static IEnumerable GetBuildLogWarnings (string path) .Where (v => v.Type == BuildLogEventType.Warning) // We're often referencing earlier .NET projects (Touch.Unit/MonoTouch.Dialog), so ignore any out-of-support warnings. .Where (v => v.Message?.Contains ("is out of support and will not receive security updates in the future") != true) + // Ignore any messages about the settings files, we get *a lot* of those + .Where (v => !(v.Message?.Contains ("The settings file '/Users/") == true && v.Message?.Contains ("/Library/Preferences/maui/Settings.plist' is deprecated, and will be ignored in .NET 11+. ") == true)) + .Where (v => !(v.Message?.Contains ("The settings file '/Users/") == true && v.Message?.Contains ("/Library/Preferences/Xamarin/Settings.plist' is deprecated, and will be ignored in .NET 11+. ") == true)) ; } diff --git a/tests/common/BundlerTool.cs b/tests/common/BundlerTool.cs index 7a5754620653..3f45c28b1bf7 100644 --- a/tests/common/BundlerTool.cs +++ b/tests/common/BundlerTool.cs @@ -321,7 +321,7 @@ public virtual void AssertExecute (string message = null) public void AssertExecuteFailure (string message = null) { - Assert.AreEqual (1, Execute (), message); + Assert.That (Execute (), Is.EqualTo (1), message); } public abstract void CreateTemporaryApp (Profile profile, string appName = "testApp", string code = null, IList extraArgs = null, string extraCode = null, string usings = null); diff --git a/tests/common/Configuration.cs b/tests/common/Configuration.cs index 3e048d52eab1..8154d4e9b100 100644 --- a/tests/common/Configuration.cs +++ b/tests/common/Configuration.cs @@ -694,7 +694,7 @@ public static void SetBuildVariables (ApplePlatform platform, [NotNullIfNotNull if (environment is null) environment = new Dictionary (); - environment ["MD_APPLE_SDK_ROOT"] = Path.GetDirectoryName (Path.GetDirectoryName (xcode_root)!)!; + environment ["DEVELOPER_DIR"] = Path.GetDirectoryName (Path.GetDirectoryName (xcode_root)!)!; // This is set by `dotnet test` and can cause building legacy projects to fail to build with: // Microsoft.NET.Build.Extensions.ConflictResolution.targets(30,5): diff --git a/tests/common/ProductTests.cs b/tests/common/ProductTests.cs index ec1d1bc53569..8d4a4d3d1063 100644 --- a/tests/common/ProductTests.cs +++ b/tests/common/ProductTests.cs @@ -71,7 +71,7 @@ public void MinOSVersion (Profile profile, MachO.LoadCommands load_command, Mach Version lc_min_version; var mincmd = lc as MinCommand; if (mincmd is not null) { - Assert.AreEqual (load_command, mincmd.Command, "Unexpected min load command"); + Assert.That (mincmd.Command, Is.EqualTo (load_command), "Unexpected min load command"); lc_min_version = mincmd.Version; } else { // starting from iOS SDK 12 the LC_BUILD_VERSION is used instead @@ -159,7 +159,7 @@ public void MinOSVersion (Profile profile, MachO.LoadCommands load_command, Mach failed.Add ($"No minOS version found in {machoFile}."); } } - CollectionAssert.IsEmpty (failed, "Failures"); + Assert.That (failed, Is.Empty, "Failures"); } } diff --git a/tests/common/TestRuntime.cs b/tests/common/TestRuntime.cs index 68ab6699c66b..296c348ac2cf 100644 --- a/tests/common/TestRuntime.cs +++ b/tests/common/TestRuntime.cs @@ -210,7 +210,7 @@ public static void AssertXcodeVersion (int major, int minor, int build = 0) if (CheckXcodeVersion (major, minor, build)) return; - NUnit.Framework.Assert.Ignore ("Requires the platform version shipped with Xcode {0}.{1}", major, minor); + NUnit.Framework.Assert.Ignore ($"Requires the platform version shipped with Xcode {major}.{minor}"); } public static void AssertDevice (string message = "This test only runs on device.") @@ -1867,7 +1867,7 @@ public static void AssertNoNonNUnitException (Exception ex, string message) case InconclusiveException: throw new InconclusiveException (ex.Message, ex); case ResultStateException: throw ex; default: - Assert.IsNull (ex, message); + Assert.That (ex, Is.Null, message); break; } } diff --git a/tests/common/Touch.Unit/Touch.Client/Runner/TestResultElement.cs b/tests/common/Touch.Unit/Touch.Client/Runner/TestResultElement.cs index 880741dcc9a2..c9f1ef8af194 100644 --- a/tests/common/Touch.Unit/Touch.Client/Runner/TestResultElement.cs +++ b/tests/common/Touch.Unit/Touch.Client/Runner/TestResultElement.cs @@ -32,7 +32,7 @@ namespace MonoTouch.NUnit.UI { class TestResultElement : StyledMultilineElement { public TestResultElement (TestResult result) : - base (result.Message ?? "Unknown error", result.StackTrace, UITableViewCellStyle.Subtitle) + base (result.Message ?? "Unknown error", result.StackTrace ?? "", UITableViewCellStyle.Subtitle) { } } diff --git a/tests/common/Touch.Unit/Touch.Client/Runner/TouchRunner.cs b/tests/common/Touch.Unit/Touch.Client/Runner/TouchRunner.cs index a2a873e133e8..1c23046fb905 100644 --- a/tests/common/Touch.Unit/Touch.Client/Runner/TouchRunner.cs +++ b/tests/common/Touch.Unit/Touch.Client/Runner/TouchRunner.cs @@ -568,8 +568,8 @@ public virtual void TestFinished (ITestResult r) #endif string? stacktrace = result.StackTrace; - if (!String.IsNullOrEmpty (result.StackTrace)) { - string [] lines = stacktrace.Split (new char [] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + if (!String.IsNullOrEmpty (stacktrace)) { + string [] lines = stacktrace!.Split (new char [] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (string line in lines) writer.WriteLine ("\t\t{0}", line); } @@ -689,9 +689,11 @@ public void Run (Test test) var tsr = new TestSuiteResult (suite); foreach (var runner in runners) { - var rv = (TestResult) (find_result (runner.Result) ?? runner.Result); - if (rv is not null) - tsr.AddResult (rv); + var runnerResult = runner.Result is not null ? (find_result (runner.Result) ?? runner.Result) : null; + if (runnerResult is null) + continue; + var rv = (TestResult) runnerResult; + tsr.AddResult (rv); } Result = tsr; #else diff --git a/tests/common/Touch.Unit/Touch.Client/dotnet/shared.csproj b/tests/common/Touch.Unit/Touch.Client/dotnet/shared.csproj index ada75cd79283..97edb9f41e74 100644 --- a/tests/common/Touch.Unit/Touch.Client/dotnet/shared.csproj +++ b/tests/common/Touch.Unit/Touch.Client/dotnet/shared.csproj @@ -55,10 +55,10 @@ - 3.12.0 + $(NUnitLitePackageVersion) - 3.6.0 + $(NUnitV2ResultWriterPackageVersion) 6.12.0.148 diff --git a/tests/common/shared-dotnet.csproj b/tests/common/shared-dotnet.csproj index 06243b83489f..8c3e83197315 100644 --- a/tests/common/shared-dotnet.csproj +++ b/tests/common/shared-dotnet.csproj @@ -107,7 +107,7 @@ - + diff --git a/tests/common/test-variations.csproj b/tests/common/test-variations.csproj index ea1da526a288..35762fdeb2dd 100644 --- a/tests/common/test-variations.csproj +++ b/tests/common/test-variations.csproj @@ -10,6 +10,7 @@ + @@ -25,6 +26,8 @@ + + @@ -68,6 +71,21 @@ <_TestVariationApplied>true + + + true + <_IsPublishing>true + full + + strict + $(DefineConstants);STATIC_NATIVE_SYMBOL_LOOKUP + + strict + managed-static + + <_TestVariationApplied>true + + partial <_TestVariationApplied>true @@ -161,6 +179,17 @@ $(DefineConstants);STATIC_NATIVE_SYMBOL_LOOKUP + + compatibility + <_TestVariationApplied>true + + + + strict + managed-static + <_TestVariationApplied>true + + <_InvalidTestVariations Include="$(TestVariation.Split('|'))" Exclude="@(TestVariations)" /> diff --git a/tests/dotnet/UnitTests/AppSizeTest.cs b/tests/dotnet/UnitTests/AppSizeTest.cs index 33ab7cbcefe5..433e142ae219 100644 --- a/tests/dotnet/UnitTests/AppSizeTest.cs +++ b/tests/dotnet/UnitTests/AppSizeTest.cs @@ -131,7 +131,8 @@ void Run (ApplePlatform platform, string runtimeIdentifiers, string configuratio DotNet.AssertBuild (project_path, properties); // FORCE_UPDATE_KNOWN_FAILURES will update the known failures files even if the test doesn't actually fail - // WRITE_KNOWN_FAILURES will only update the known failures files if the test fails + // WRITE_KNOWN_FAILURES will only update the known failures files if the test fails (and mark the test as passed) + // If neither is set, the updated expected file is uploaded as an Azure DevOps artifact. var forceUpdate = !string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("FORCE_UPDATE_KNOWN_FAILURES")); var update = forceUpdate || !string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("WRITE_KNOWN_FAILURES")); @@ -184,30 +185,21 @@ static void AssertAppSize (ApplePlatform platform, string name, string appPath, msg = $"App size changed significantly ({FormatBytes (appSizeDifference, true)} different > tolerance of +-{FormatBytes (toleranceInBytes)}). Expected app size: {FormatBytes (expectedAppBundleSize)}, actual app size: {FormatBytes (appBundleSize)}."; } - var updated = false; - if (forceUpdate || (update && !withinTolerance)) { - Directory.CreateDirectory (expectedDirectory); - File.WriteAllText (expectedSizeReportPath, report.ToString ()); - msg += " Check the modified files for more information."; - updated = true; - } else if (!withinTolerance) { - msg += " Set the environment variable WRITE_KNOWN_FAILURES=1, run the test again, and verify the modified files for more information."; - } - Console.WriteLine ($" {msg}"); + // Compare individual files in the app bundle var expectedLines = expectedSizeReport.SplitLines ().Skip (2).Where (v => v.IndexOf (':') >= 0).ToDictionary (v => v [..v.IndexOf (':')], v => v [(v.IndexOf (':') + 1)..]); var actualLines = report.ToString ().SplitLines ().Skip (2).Where (v => v.IndexOf (':') >= 0).ToDictionary (v => v [..v.IndexOf (':')], v => v [(v.IndexOf (':') + 1)..]); var allKeys = expectedLines.Keys.Union (actualLines.Keys).OrderBy (v => v); + var filesAdded = new List (); + var filesRemoved = new List (); foreach (var key in allKeys) { if (!expectedLines.TryGetValue (key, out var expectedLine)) { Console.WriteLine ($" File '{key}' was added to app bundle: {actualLines [key]}"); - if (!updated) - Assert.Fail ($"The file '{key}' was added to the app bundle."); + filesAdded.Add (key); } else if (!actualLines.TryGetValue (key, out var actualLine)) { Console.WriteLine ($" File '{key}' was removed from app bundle: {expectedLine}"); - if (!updated) - Assert.Fail ($"The file '{key}' was removed from the app bundle."); + filesRemoved.Add (key); } else if (expectedLine != actualLine) { Console.WriteLine ($" File '{key}' changed in app bundle:"); Console.WriteLine ($" -{expectedLine}"); @@ -215,8 +207,27 @@ static void AssertAppSize (ApplePlatform platform, string name, string appPath, } } - if (!updated && !withinTolerance) - Assert.Fail (msg); + // Determine if there are any meaningful differences + var hasFileDifferences = filesAdded.Count > 0 || filesRemoved.Count > 0; + var hasSizeDifference = !withinTolerance; + var hasDifferences = hasFileDifferences || hasSizeDifference; + + if (forceUpdate || (update && hasDifferences)) { + Directory.CreateDirectory (expectedDirectory); + File.WriteAllText (expectedSizeReportPath, report.ToString ()); + Console.WriteLine ($" Updated expected file: {expectedSizeReportPath}"); + } else if (hasDifferences) { + UploadUpdatedExpectedFile (expectedSizeReportPath, report.ToString ()); + if (hasFileDifferences) { + var details = new List (); + foreach (var key in filesAdded) + details.Add ($"added: '{key}'"); + foreach (var key in filesRemoved) + details.Add ($"removed: '{key}'"); + Assert.Fail ($"The app bundle's file list changed ({string.Join (", ", details)}). The updated expected file is available as a build artifact (set WRITE_KNOWN_FAILURES=1 to update locally)."); + } + Assert.Fail ($"{msg} The updated expected file is available as a build artifact (set WRITE_KNOWN_FAILURES=1 to update locally)."); + } } // Create a file with all the APIs that survived the trimmer; this can be useful to determine what is not trimmed away. @@ -255,9 +266,29 @@ void AssertAssemblyReport (ApplePlatform platform, string name, string appPath, } if (!update) { - Assert.That (addedAPIs, Is.Empty, "No added APIs (set the environment variable WRITE_KNOWN_FAILURES=1 and run the test again to update the expected set of APIs)"); - Assert.That (removedAPIs, Is.Empty, "No removed APIs (set the environment variable WRITE_KNOWN_FAILURES=1 and run the test again to update the expected set of APIs)"); + if (addedAPIs.Count > 0 || removedAPIs.Count > 0) { + UploadUpdatedExpectedFile (expectedFile, string.Join ('\n', preservedAPIs) + "\n"); + var updateMsg = " The updated expected file is available as a build artifact (set WRITE_KNOWN_FAILURES=1 to update locally)."; + Assert.That (addedAPIs, Is.Empty, "No added APIs." + updateMsg); + Assert.That (removedAPIs, Is.Empty, "No removed APIs." + updateMsg); + } + } + } + + static void UploadUpdatedExpectedFile (string expectedFilePath, string content) + { + var fileName = Path.GetFileName (expectedFilePath); + var artifactStagingDir = Environment.GetEnvironmentVariable ("BUILD_ARTIFACTSTAGINGDIRECTORY"); + string outputDir; + if (!string.IsNullOrEmpty (artifactStagingDir)) { + outputDir = Path.Combine (artifactStagingDir, "updated-expected-sizes"); + } else { + outputDir = Path.Combine (Cache.CreateTemporaryDirectory ("AppSizeTest"), "updated-expected-sizes"); } + Directory.CreateDirectory (outputDir); + var outputFile = Path.Combine (outputDir, fileName); + File.WriteAllText (outputFile, content); + Console.WriteLine ($" Updated expected file written to: {outputFile}"); } static string FormatBytes (long bytes, bool alwaysShowSign = false) diff --git a/tests/dotnet/UnitTests/RegistrarTest.cs b/tests/dotnet/UnitTests/RegistrarTest.cs index 003efbdc3281..f7aad07cb565 100644 --- a/tests/dotnet/UnitTests/RegistrarTest.cs +++ b/tests/dotnet/UnitTests/RegistrarTest.cs @@ -76,6 +76,7 @@ public void ClassRewriterTest (ApplePlatform platform, bool rewriteHandles) // enable the linker (so that the main assembly is modified) properties ["LinkMode"] = "full"; properties ["MtouchLink"] = "full"; + properties ["InlineClassGetHandle"] = "disabled"; if (rewriteHandles) properties ["MtouchExtraArgs"] = "--optimize=redirect-class-handles"; diff --git a/tests/dotnet/UnitTests/XcodeVersionTest.cs b/tests/dotnet/UnitTests/XcodeVersionTest.cs index a365af92f75e..301eb5e57fe0 100644 --- a/tests/dotnet/UnitTests/XcodeVersionTest.cs +++ b/tests/dotnet/UnitTests/XcodeVersionTest.cs @@ -35,16 +35,11 @@ public void Test (ApplePlatform platform, string xcodePath, Version xcodeVersion Clean (project_path); var properties = GetDefaultProperties (runtimeIdentifiers); properties ["BundleOriginalResources"] = "true"; // this prevents a different and unrelated error message from failing to build library projects + properties ["XcodeLocation"] = xcodePath; - var existingDeveloperDir = Environment.GetEnvironmentVariable ("MD_APPLE_SDK_ROOT"); - try { - Environment.SetEnvironmentVariable ("MD_APPLE_SDK_ROOT", Path.GetDirectoryName (Path.GetDirectoryName (xcodePath))); - var rv = DotNet.AssertBuildFailure (project_path, properties); - var errors = BinLog.GetBuildLogErrors (rv.BinLogPath).ToArray (); - AssertErrorMessages (errors, $"This version of .NET for {platform.AsString ()} ({Configuration.GetNuGetVersionNoMetadata (platform)}) requires Xcode {Configuration.XcodeVersion}. The current version of Xcode is {xcodeVersion}. Either install Xcode {Configuration.XcodeVersion}, or use a different version of .NET for {platform.AsString ()}. See https://aka.ms/xcode-requirement for more information."); - } finally { - Environment.SetEnvironmentVariable ("MD_APPLE_SDK_ROOT", existingDeveloperDir); - } + var rv = DotNet.AssertBuildFailure (project_path, properties); + var errors = BinLog.GetBuildLogErrors (rv.BinLogPath).ToArray (); + AssertErrorMessages (errors, $"This version of .NET for {platform.AsString ()} ({Configuration.GetNuGetVersionNoMetadata (platform)}) requires Xcode {Configuration.XcodeVersion}. The current version of Xcode is {xcodeVersion}. Either install Xcode {Configuration.XcodeVersion}, or use a different version of .NET for {platform.AsString ()}. See https://aka.ms/xcode-requirement for more information."); } } } diff --git a/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-interpreter-preservedapis.txt b/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-interpreter-preservedapis.txt index c7c2da2860f1..c892d1141145 100644 --- a/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-interpreter-preservedapis.txt +++ b/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-interpreter-preservedapis.txt @@ -195,12 +195,9 @@ Microsoft.MacCatalyst.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NS Microsoft.MacCatalyst.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::InitialSet Microsoft.MacCatalyst.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::None Microsoft.MacCatalyst.dll:Foundation.NSObjectData -Microsoft.MacCatalyst.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::data Microsoft.MacCatalyst.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::Data() Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle..ctor() -Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle.CreateHandle(Foundation.NSObject) -Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle.Finalize() Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle.get_Data() Microsoft.MacCatalyst.dll:Foundation.NSObjectFlag Microsoft.MacCatalyst.dll:Foundation.NSObjectFlag Foundation.NSObjectFlag::Empty @@ -252,6 +249,12 @@ Microsoft.MacCatalyst.dll:Foundation.RegisterAttribute.get_IsStubClass() Microsoft.MacCatalyst.dll:Foundation.RegisterAttribute.get_IsWrapper() Microsoft.MacCatalyst.dll:Foundation.RegisterAttribute.get_Name() Microsoft.MacCatalyst.dll:Foundation.RegisterAttribute.get_SkipRegistration() +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory..ctor(System.UIntPtr) +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory.CreateHandle(Foundation.NSObject) +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory.Finalize() +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory.get_Value() +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory.set_Value(System.IntPtr) Microsoft.MacCatalyst.dll:Foundation.You_Should_Not_Call_base_In_This_Method Microsoft.MacCatalyst.dll:Foundation.You_Should_Not_Call_base_In_This_Method..ctor() Microsoft.MacCatalyst.dll:ObjCRuntime.__Registrar__ @@ -495,7 +498,6 @@ Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObject::class_pt Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObject::ClassHandle() Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObject::handle() Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObject::Handle() -Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::classHandle Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::handle Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSString::class_ptr Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSString::ClassHandle() @@ -592,7 +594,6 @@ Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.g__Constru Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.g__ConstructNSObjectViaFactoryMethod|288_0`1(ObjCRuntime.NativeHandle) Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object, System.Runtime.InteropServices.GCHandleType) Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object) -Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AllocZeroed`1() Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AppendAdditionalInformation(System.Text.StringBuilder, System.IntPtr, System.RuntimeMethodHandle) Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.attempt_retain_nsobject(System.IntPtr, System.IntPtr*) Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AttemptRetainNSObject(System.IntPtr) @@ -1334,6 +1335,8 @@ Microsoft.MacCatalyst.dll:System.IntPtr CoreFoundation.CFRange::len Microsoft.MacCatalyst.dll:System.IntPtr CoreFoundation.CFRange::loc Microsoft.MacCatalyst.dll:System.IntPtr Foundation.NSObject::__data Microsoft.MacCatalyst.dll:System.IntPtr Foundation.NSObject/NSObject_Disposer::class_ptr +Microsoft.MacCatalyst.dll:System.IntPtr Foundation.TrackedMemory::k__BackingField +Microsoft.MacCatalyst.dll:System.IntPtr Foundation.TrackedMemory::Value() Microsoft.MacCatalyst.dll:System.IntPtr ObjCRuntime.AdoptsAttribute::ProtocolHandle() Microsoft.MacCatalyst.dll:System.IntPtr ObjCRuntime.BlockCollector::block Microsoft.MacCatalyst.dll:System.IntPtr ObjCRuntime.Libraries/CoreFoundation::Handle @@ -1497,9 +1500,10 @@ Microsoft.MacCatalyst.dll:System.Reflection.MethodBase Registrar.Registrar/ObjCM Microsoft.MacCatalyst.dll:System.Reflection.PropertyInfo Registrar.Registrar/ObjCProperty::Property Microsoft.MacCatalyst.dll:System.Reflection.TypeFilter Registrar.SharedDynamic/<>c::<>9__0_0 Microsoft.MacCatalyst.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::data_table +Microsoft.MacCatalyst.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::super_map Microsoft.MacCatalyst.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Runtime::block_lifetime_table Microsoft.MacCatalyst.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Class::assembly_to_name -Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.GCHandle Foundation.NSObjectDataHandle::handle +Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.GCHandle Foundation.TrackedMemory::handle Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::height Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::width Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::x diff --git a/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-preservedapis.txt b/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-preservedapis.txt index ff8f163f0c33..0ee0a83429a6 100644 --- a/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-preservedapis.txt +++ b/tests/dotnet/UnitTests/expected/MacCatalyst-MonoVM-preservedapis.txt @@ -178,12 +178,9 @@ Microsoft.MacCatalyst.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NS Microsoft.MacCatalyst.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::InitialSet Microsoft.MacCatalyst.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::None Microsoft.MacCatalyst.dll:Foundation.NSObjectData -Microsoft.MacCatalyst.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::data Microsoft.MacCatalyst.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::Data() Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle..ctor() -Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle.CreateHandle(Foundation.NSObject) -Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle.Finalize() Microsoft.MacCatalyst.dll:Foundation.NSObjectDataHandle.get_Data() Microsoft.MacCatalyst.dll:Foundation.NSObjectFlag Microsoft.MacCatalyst.dll:Foundation.NSObjectFlag Foundation.NSObjectFlag::Empty @@ -194,6 +191,12 @@ Microsoft.MacCatalyst.dll:Foundation.RegisterAttribute Microsoft.MacCatalyst.dll:Foundation.RegisterAttribute..ctor(System.String, System.Boolean) Microsoft.MacCatalyst.dll:Foundation.RegisterAttribute..ctor(System.String) Microsoft.MacCatalyst.dll:Foundation.RegisterAttribute.get_IsWrapper() +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory..ctor(System.UIntPtr) +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory.CreateHandle(Foundation.NSObject) +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory.Finalize() +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory.get_Value() +Microsoft.MacCatalyst.dll:Foundation.TrackedMemory.set_Value(System.IntPtr) Microsoft.MacCatalyst.dll:Foundation.You_Should_Not_Call_base_In_This_Method Microsoft.MacCatalyst.dll:Foundation.You_Should_Not_Call_base_In_This_Method..ctor() Microsoft.MacCatalyst.dll:ObjCRuntime.__Registrar__ @@ -375,7 +378,6 @@ Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObject::class_pt Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObject::ClassHandle() Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObject::handle() Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObject::Handle() -Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::classHandle Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::handle Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle ObjCRuntime.Class::handle Microsoft.MacCatalyst.dll:ObjCRuntime.NativeHandle ObjCRuntime.Class::Handle() @@ -450,7 +452,6 @@ Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.g__Constru Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.g__ConstructNSObjectViaFactoryMethod|288_0`1(ObjCRuntime.NativeHandle) Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object, System.Runtime.InteropServices.GCHandleType) Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object) -Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AllocZeroed`1() Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AppendAdditionalInformation(System.Text.StringBuilder, System.IntPtr, System.RuntimeMethodHandle) Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.attempt_retain_nsobject(System.IntPtr, System.IntPtr*) Microsoft.MacCatalyst.dll:ObjCRuntime.Runtime.AttemptRetainNSObject(System.IntPtr) @@ -721,6 +722,8 @@ Microsoft.MacCatalyst.dll:System.IntPtr CoreFoundation.CFRange::len Microsoft.MacCatalyst.dll:System.IntPtr CoreFoundation.CFRange::loc Microsoft.MacCatalyst.dll:System.IntPtr Foundation.NSObject::__data Microsoft.MacCatalyst.dll:System.IntPtr Foundation.NSObject/NSObject_Disposer::class_ptr +Microsoft.MacCatalyst.dll:System.IntPtr Foundation.TrackedMemory::k__BackingField +Microsoft.MacCatalyst.dll:System.IntPtr Foundation.TrackedMemory::Value() Microsoft.MacCatalyst.dll:System.IntPtr ObjCRuntime.BlockCollector::block Microsoft.MacCatalyst.dll:System.IntPtr ObjCRuntime.Libraries/CoreFoundation::Handle Microsoft.MacCatalyst.dll:System.IntPtr ObjCRuntime.NativeHandle::handle @@ -852,9 +855,10 @@ Microsoft.MacCatalyst.dll:System.Object ObjCRuntime.Class::verification_lock Microsoft.MacCatalyst.dll:System.Object ObjCRuntime.Runtime::lock_obj Microsoft.MacCatalyst.dll:System.Reflection.Assembly Foundation.NSObject::PlatformAssembly Microsoft.MacCatalyst.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::data_table +Microsoft.MacCatalyst.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::super_map Microsoft.MacCatalyst.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Runtime::block_lifetime_table Microsoft.MacCatalyst.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Class::assembly_to_name -Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.GCHandle Foundation.NSObjectDataHandle::handle +Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.GCHandle Foundation.TrackedMemory::handle Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::height Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::width Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::x diff --git a/tests/dotnet/UnitTests/expected/TVOS-MonoVM-interpreter-preservedapis.txt b/tests/dotnet/UnitTests/expected/TVOS-MonoVM-interpreter-preservedapis.txt index 23d1748debc9..1fe483d5e304 100644 --- a/tests/dotnet/UnitTests/expected/TVOS-MonoVM-interpreter-preservedapis.txt +++ b/tests/dotnet/UnitTests/expected/TVOS-MonoVM-interpreter-preservedapis.txt @@ -187,12 +187,9 @@ Microsoft.tvOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/ Microsoft.tvOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::InitialSet Microsoft.tvOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::None Microsoft.tvOS.dll:Foundation.NSObjectData -Microsoft.tvOS.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::data Microsoft.tvOS.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::Data() Microsoft.tvOS.dll:Foundation.NSObjectDataHandle Microsoft.tvOS.dll:Foundation.NSObjectDataHandle..ctor() -Microsoft.tvOS.dll:Foundation.NSObjectDataHandle.CreateHandle(Foundation.NSObject) -Microsoft.tvOS.dll:Foundation.NSObjectDataHandle.Finalize() Microsoft.tvOS.dll:Foundation.NSObjectDataHandle.get_Data() Microsoft.tvOS.dll:Foundation.NSObjectFlag Microsoft.tvOS.dll:Foundation.NSObjectFlag Foundation.NSObjectFlag::Empty @@ -244,6 +241,12 @@ Microsoft.tvOS.dll:Foundation.RegisterAttribute.get_IsStubClass() Microsoft.tvOS.dll:Foundation.RegisterAttribute.get_IsWrapper() Microsoft.tvOS.dll:Foundation.RegisterAttribute.get_Name() Microsoft.tvOS.dll:Foundation.RegisterAttribute.get_SkipRegistration() +Microsoft.tvOS.dll:Foundation.TrackedMemory +Microsoft.tvOS.dll:Foundation.TrackedMemory..ctor(System.UIntPtr) +Microsoft.tvOS.dll:Foundation.TrackedMemory.CreateHandle(Foundation.NSObject) +Microsoft.tvOS.dll:Foundation.TrackedMemory.Finalize() +Microsoft.tvOS.dll:Foundation.TrackedMemory.get_Value() +Microsoft.tvOS.dll:Foundation.TrackedMemory.set_Value(System.IntPtr) Microsoft.tvOS.dll:Foundation.You_Should_Not_Call_base_In_This_Method Microsoft.tvOS.dll:Foundation.You_Should_Not_Call_base_In_This_Method..ctor() Microsoft.tvOS.dll:ObjCRuntime.__Registrar__ @@ -490,7 +493,6 @@ Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::class_ptr Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::ClassHandle() Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::handle() Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::Handle() -Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::classHandle Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::handle Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSString::class_ptr Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSString::ClassHandle() @@ -588,7 +590,6 @@ Microsoft.tvOS.dll:ObjCRuntime.Runtime.g__ConstructINati Microsoft.tvOS.dll:ObjCRuntime.Runtime.g__ConstructNSObjectViaFactoryMethod|288_0`1(ObjCRuntime.NativeHandle) Microsoft.tvOS.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object, System.Runtime.InteropServices.GCHandleType) Microsoft.tvOS.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object) -Microsoft.tvOS.dll:ObjCRuntime.Runtime.AllocZeroed`1() Microsoft.tvOS.dll:ObjCRuntime.Runtime.AppendAdditionalInformation(System.Text.StringBuilder, System.IntPtr, System.RuntimeMethodHandle) Microsoft.tvOS.dll:ObjCRuntime.Runtime.attempt_retain_nsobject(System.IntPtr, System.IntPtr*) Microsoft.tvOS.dll:ObjCRuntime.Runtime.AttemptRetainNSObject(System.IntPtr) @@ -1324,6 +1325,8 @@ Microsoft.tvOS.dll:System.IntPtr CoreFoundation.CFRange::len Microsoft.tvOS.dll:System.IntPtr CoreFoundation.CFRange::loc Microsoft.tvOS.dll:System.IntPtr Foundation.NSObject::__data Microsoft.tvOS.dll:System.IntPtr Foundation.NSObject/NSObject_Disposer::class_ptr +Microsoft.tvOS.dll:System.IntPtr Foundation.TrackedMemory::k__BackingField +Microsoft.tvOS.dll:System.IntPtr Foundation.TrackedMemory::Value() Microsoft.tvOS.dll:System.IntPtr ObjCRuntime.AdoptsAttribute::ProtocolHandle() Microsoft.tvOS.dll:System.IntPtr ObjCRuntime.BlockCollector::block Microsoft.tvOS.dll:System.IntPtr ObjCRuntime.Libraries/CoreFoundation::Handle @@ -1485,9 +1488,10 @@ Microsoft.tvOS.dll:System.Reflection.MethodBase Registrar.Registrar/ObjCMethod:: Microsoft.tvOS.dll:System.Reflection.PropertyInfo Registrar.Registrar/ObjCProperty::Property Microsoft.tvOS.dll:System.Reflection.TypeFilter Registrar.SharedDynamic/<>c::<>9__0_0 Microsoft.tvOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::data_table +Microsoft.tvOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::super_map Microsoft.tvOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Runtime::block_lifetime_table Microsoft.tvOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Class::assembly_to_name -Microsoft.tvOS.dll:System.Runtime.InteropServices.GCHandle Foundation.NSObjectDataHandle::handle +Microsoft.tvOS.dll:System.Runtime.InteropServices.GCHandle Foundation.TrackedMemory::handle Microsoft.tvOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::height Microsoft.tvOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::width Microsoft.tvOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::x diff --git a/tests/dotnet/UnitTests/expected/TVOS-MonoVM-preservedapis.txt b/tests/dotnet/UnitTests/expected/TVOS-MonoVM-preservedapis.txt index 0067b7a14131..9fd004271447 100644 --- a/tests/dotnet/UnitTests/expected/TVOS-MonoVM-preservedapis.txt +++ b/tests/dotnet/UnitTests/expected/TVOS-MonoVM-preservedapis.txt @@ -170,12 +170,9 @@ Microsoft.tvOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/ Microsoft.tvOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::InitialSet Microsoft.tvOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::None Microsoft.tvOS.dll:Foundation.NSObjectData -Microsoft.tvOS.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::data Microsoft.tvOS.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::Data() Microsoft.tvOS.dll:Foundation.NSObjectDataHandle Microsoft.tvOS.dll:Foundation.NSObjectDataHandle..ctor() -Microsoft.tvOS.dll:Foundation.NSObjectDataHandle.CreateHandle(Foundation.NSObject) -Microsoft.tvOS.dll:Foundation.NSObjectDataHandle.Finalize() Microsoft.tvOS.dll:Foundation.NSObjectDataHandle.get_Data() Microsoft.tvOS.dll:Foundation.NSObjectFlag Microsoft.tvOS.dll:Foundation.NSObjectFlag Foundation.NSObjectFlag::Empty @@ -186,6 +183,12 @@ Microsoft.tvOS.dll:Foundation.RegisterAttribute Microsoft.tvOS.dll:Foundation.RegisterAttribute..ctor(System.String, System.Boolean) Microsoft.tvOS.dll:Foundation.RegisterAttribute..ctor(System.String) Microsoft.tvOS.dll:Foundation.RegisterAttribute.get_IsWrapper() +Microsoft.tvOS.dll:Foundation.TrackedMemory +Microsoft.tvOS.dll:Foundation.TrackedMemory..ctor(System.UIntPtr) +Microsoft.tvOS.dll:Foundation.TrackedMemory.CreateHandle(Foundation.NSObject) +Microsoft.tvOS.dll:Foundation.TrackedMemory.Finalize() +Microsoft.tvOS.dll:Foundation.TrackedMemory.get_Value() +Microsoft.tvOS.dll:Foundation.TrackedMemory.set_Value(System.IntPtr) Microsoft.tvOS.dll:Foundation.You_Should_Not_Call_base_In_This_Method Microsoft.tvOS.dll:Foundation.You_Should_Not_Call_base_In_This_Method..ctor() Microsoft.tvOS.dll:ObjCRuntime.__Registrar__ @@ -370,7 +373,6 @@ Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::class_ptr Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::ClassHandle() Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::handle() Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::Handle() -Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::classHandle Microsoft.tvOS.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::handle Microsoft.tvOS.dll:ObjCRuntime.NativeHandle ObjCRuntime.Class::handle Microsoft.tvOS.dll:ObjCRuntime.NativeHandle ObjCRuntime.Class::Handle() @@ -446,7 +448,6 @@ Microsoft.tvOS.dll:ObjCRuntime.Runtime.g__ConstructINati Microsoft.tvOS.dll:ObjCRuntime.Runtime.g__ConstructNSObjectViaFactoryMethod|288_0`1(ObjCRuntime.NativeHandle) Microsoft.tvOS.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object, System.Runtime.InteropServices.GCHandleType) Microsoft.tvOS.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object) -Microsoft.tvOS.dll:ObjCRuntime.Runtime.AllocZeroed`1() Microsoft.tvOS.dll:ObjCRuntime.Runtime.AppendAdditionalInformation(System.Text.StringBuilder, System.IntPtr, System.RuntimeMethodHandle) Microsoft.tvOS.dll:ObjCRuntime.Runtime.attempt_retain_nsobject(System.IntPtr, System.IntPtr*) Microsoft.tvOS.dll:ObjCRuntime.Runtime.AttemptRetainNSObject(System.IntPtr) @@ -716,6 +717,8 @@ Microsoft.tvOS.dll:System.IntPtr CoreFoundation.CFRange::len Microsoft.tvOS.dll:System.IntPtr CoreFoundation.CFRange::loc Microsoft.tvOS.dll:System.IntPtr Foundation.NSObject::__data Microsoft.tvOS.dll:System.IntPtr Foundation.NSObject/NSObject_Disposer::class_ptr +Microsoft.tvOS.dll:System.IntPtr Foundation.TrackedMemory::k__BackingField +Microsoft.tvOS.dll:System.IntPtr Foundation.TrackedMemory::Value() Microsoft.tvOS.dll:System.IntPtr ObjCRuntime.BlockCollector::block Microsoft.tvOS.dll:System.IntPtr ObjCRuntime.Libraries/CoreFoundation::Handle Microsoft.tvOS.dll:System.IntPtr ObjCRuntime.NativeHandle::handle @@ -845,9 +848,10 @@ Microsoft.tvOS.dll:System.Object Foundation.NSObject/NSObject_Disposer::lock_obj Microsoft.tvOS.dll:System.Object ObjCRuntime.Runtime::lock_obj Microsoft.tvOS.dll:System.Reflection.Assembly Foundation.NSObject::PlatformAssembly Microsoft.tvOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::data_table +Microsoft.tvOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::super_map Microsoft.tvOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Runtime::block_lifetime_table Microsoft.tvOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Class::assembly_to_name -Microsoft.tvOS.dll:System.Runtime.InteropServices.GCHandle Foundation.NSObjectDataHandle::handle +Microsoft.tvOS.dll:System.Runtime.InteropServices.GCHandle Foundation.TrackedMemory::handle Microsoft.tvOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::height Microsoft.tvOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::width Microsoft.tvOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::x diff --git a/tests/dotnet/UnitTests/expected/iOS-MonoVM-interpreter-preservedapis.txt b/tests/dotnet/UnitTests/expected/iOS-MonoVM-interpreter-preservedapis.txt index e6bc0a0de743..d841183c5eaf 100644 --- a/tests/dotnet/UnitTests/expected/iOS-MonoVM-interpreter-preservedapis.txt +++ b/tests/dotnet/UnitTests/expected/iOS-MonoVM-interpreter-preservedapis.txt @@ -187,12 +187,9 @@ Microsoft.iOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/X Microsoft.iOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::InitialSet Microsoft.iOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::None Microsoft.iOS.dll:Foundation.NSObjectData -Microsoft.iOS.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::data Microsoft.iOS.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::Data() Microsoft.iOS.dll:Foundation.NSObjectDataHandle Microsoft.iOS.dll:Foundation.NSObjectDataHandle..ctor() -Microsoft.iOS.dll:Foundation.NSObjectDataHandle.CreateHandle(Foundation.NSObject) -Microsoft.iOS.dll:Foundation.NSObjectDataHandle.Finalize() Microsoft.iOS.dll:Foundation.NSObjectDataHandle.get_Data() Microsoft.iOS.dll:Foundation.NSObjectFlag Microsoft.iOS.dll:Foundation.NSObjectFlag Foundation.NSObjectFlag::Empty @@ -244,6 +241,12 @@ Microsoft.iOS.dll:Foundation.RegisterAttribute.get_IsStubClass() Microsoft.iOS.dll:Foundation.RegisterAttribute.get_IsWrapper() Microsoft.iOS.dll:Foundation.RegisterAttribute.get_Name() Microsoft.iOS.dll:Foundation.RegisterAttribute.get_SkipRegistration() +Microsoft.iOS.dll:Foundation.TrackedMemory +Microsoft.iOS.dll:Foundation.TrackedMemory..ctor(System.UIntPtr) +Microsoft.iOS.dll:Foundation.TrackedMemory.CreateHandle(Foundation.NSObject) +Microsoft.iOS.dll:Foundation.TrackedMemory.Finalize() +Microsoft.iOS.dll:Foundation.TrackedMemory.get_Value() +Microsoft.iOS.dll:Foundation.TrackedMemory.set_Value(System.IntPtr) Microsoft.iOS.dll:Foundation.You_Should_Not_Call_base_In_This_Method Microsoft.iOS.dll:Foundation.You_Should_Not_Call_base_In_This_Method..ctor() Microsoft.iOS.dll:ObjCRuntime.__Registrar__ @@ -490,7 +493,6 @@ Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::class_ptr Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::ClassHandle() Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::handle() Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::Handle() -Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::classHandle Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::handle Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSString::class_ptr Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSString::ClassHandle() @@ -588,7 +590,6 @@ Microsoft.iOS.dll:ObjCRuntime.Runtime.g__ConstructINativ Microsoft.iOS.dll:ObjCRuntime.Runtime.g__ConstructNSObjectViaFactoryMethod|288_0`1(ObjCRuntime.NativeHandle) Microsoft.iOS.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object, System.Runtime.InteropServices.GCHandleType) Microsoft.iOS.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object) -Microsoft.iOS.dll:ObjCRuntime.Runtime.AllocZeroed`1() Microsoft.iOS.dll:ObjCRuntime.Runtime.AppendAdditionalInformation(System.Text.StringBuilder, System.IntPtr, System.RuntimeMethodHandle) Microsoft.iOS.dll:ObjCRuntime.Runtime.attempt_retain_nsobject(System.IntPtr, System.IntPtr*) Microsoft.iOS.dll:ObjCRuntime.Runtime.AttemptRetainNSObject(System.IntPtr) @@ -1324,6 +1325,8 @@ Microsoft.iOS.dll:System.IntPtr CoreFoundation.CFRange::len Microsoft.iOS.dll:System.IntPtr CoreFoundation.CFRange::loc Microsoft.iOS.dll:System.IntPtr Foundation.NSObject::__data Microsoft.iOS.dll:System.IntPtr Foundation.NSObject/NSObject_Disposer::class_ptr +Microsoft.iOS.dll:System.IntPtr Foundation.TrackedMemory::k__BackingField +Microsoft.iOS.dll:System.IntPtr Foundation.TrackedMemory::Value() Microsoft.iOS.dll:System.IntPtr ObjCRuntime.AdoptsAttribute::ProtocolHandle() Microsoft.iOS.dll:System.IntPtr ObjCRuntime.BlockCollector::block Microsoft.iOS.dll:System.IntPtr ObjCRuntime.Libraries/CoreFoundation::Handle @@ -1485,9 +1488,10 @@ Microsoft.iOS.dll:System.Reflection.MethodBase Registrar.Registrar/ObjCMethod::M Microsoft.iOS.dll:System.Reflection.PropertyInfo Registrar.Registrar/ObjCProperty::Property Microsoft.iOS.dll:System.Reflection.TypeFilter Registrar.SharedDynamic/<>c::<>9__0_0 Microsoft.iOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::data_table +Microsoft.iOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::super_map Microsoft.iOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Runtime::block_lifetime_table Microsoft.iOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Class::assembly_to_name -Microsoft.iOS.dll:System.Runtime.InteropServices.GCHandle Foundation.NSObjectDataHandle::handle +Microsoft.iOS.dll:System.Runtime.InteropServices.GCHandle Foundation.TrackedMemory::handle Microsoft.iOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::height Microsoft.iOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::width Microsoft.iOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::x diff --git a/tests/dotnet/UnitTests/expected/iOS-MonoVM-preservedapis.txt b/tests/dotnet/UnitTests/expected/iOS-MonoVM-preservedapis.txt index f42a3a8a15ef..6fb32b4c79df 100644 --- a/tests/dotnet/UnitTests/expected/iOS-MonoVM-preservedapis.txt +++ b/tests/dotnet/UnitTests/expected/iOS-MonoVM-preservedapis.txt @@ -170,12 +170,9 @@ Microsoft.iOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/X Microsoft.iOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::InitialSet Microsoft.iOS.dll:Foundation.NSObject/XamarinGCHandleFlags Foundation.NSObject/XamarinGCHandleFlags::None Microsoft.iOS.dll:Foundation.NSObjectData -Microsoft.iOS.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::data Microsoft.iOS.dll:Foundation.NSObjectData* Foundation.NSObjectDataHandle::Data() Microsoft.iOS.dll:Foundation.NSObjectDataHandle Microsoft.iOS.dll:Foundation.NSObjectDataHandle..ctor() -Microsoft.iOS.dll:Foundation.NSObjectDataHandle.CreateHandle(Foundation.NSObject) -Microsoft.iOS.dll:Foundation.NSObjectDataHandle.Finalize() Microsoft.iOS.dll:Foundation.NSObjectDataHandle.get_Data() Microsoft.iOS.dll:Foundation.NSObjectFlag Microsoft.iOS.dll:Foundation.NSObjectFlag Foundation.NSObjectFlag::Empty @@ -186,6 +183,12 @@ Microsoft.iOS.dll:Foundation.RegisterAttribute Microsoft.iOS.dll:Foundation.RegisterAttribute..ctor(System.String, System.Boolean) Microsoft.iOS.dll:Foundation.RegisterAttribute..ctor(System.String) Microsoft.iOS.dll:Foundation.RegisterAttribute.get_IsWrapper() +Microsoft.iOS.dll:Foundation.TrackedMemory +Microsoft.iOS.dll:Foundation.TrackedMemory..ctor(System.UIntPtr) +Microsoft.iOS.dll:Foundation.TrackedMemory.CreateHandle(Foundation.NSObject) +Microsoft.iOS.dll:Foundation.TrackedMemory.Finalize() +Microsoft.iOS.dll:Foundation.TrackedMemory.get_Value() +Microsoft.iOS.dll:Foundation.TrackedMemory.set_Value(System.IntPtr) Microsoft.iOS.dll:Foundation.You_Should_Not_Call_base_In_This_Method Microsoft.iOS.dll:Foundation.You_Should_Not_Call_base_In_This_Method..ctor() Microsoft.iOS.dll:ObjCRuntime.__Registrar__ @@ -370,7 +373,6 @@ Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::class_ptr Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::ClassHandle() Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::handle() Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObject::Handle() -Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::classHandle Microsoft.iOS.dll:ObjCRuntime.NativeHandle Foundation.NSObjectData::handle Microsoft.iOS.dll:ObjCRuntime.NativeHandle ObjCRuntime.Class::handle Microsoft.iOS.dll:ObjCRuntime.NativeHandle ObjCRuntime.Class::Handle() @@ -446,7 +448,6 @@ Microsoft.iOS.dll:ObjCRuntime.Runtime.g__ConstructINativ Microsoft.iOS.dll:ObjCRuntime.Runtime.g__ConstructNSObjectViaFactoryMethod|288_0`1(ObjCRuntime.NativeHandle) Microsoft.iOS.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object, System.Runtime.InteropServices.GCHandleType) Microsoft.iOS.dll:ObjCRuntime.Runtime.AllocGCHandle(System.Object) -Microsoft.iOS.dll:ObjCRuntime.Runtime.AllocZeroed`1() Microsoft.iOS.dll:ObjCRuntime.Runtime.AppendAdditionalInformation(System.Text.StringBuilder, System.IntPtr, System.RuntimeMethodHandle) Microsoft.iOS.dll:ObjCRuntime.Runtime.attempt_retain_nsobject(System.IntPtr, System.IntPtr*) Microsoft.iOS.dll:ObjCRuntime.Runtime.AttemptRetainNSObject(System.IntPtr) @@ -716,6 +717,8 @@ Microsoft.iOS.dll:System.IntPtr CoreFoundation.CFRange::len Microsoft.iOS.dll:System.IntPtr CoreFoundation.CFRange::loc Microsoft.iOS.dll:System.IntPtr Foundation.NSObject::__data Microsoft.iOS.dll:System.IntPtr Foundation.NSObject/NSObject_Disposer::class_ptr +Microsoft.iOS.dll:System.IntPtr Foundation.TrackedMemory::k__BackingField +Microsoft.iOS.dll:System.IntPtr Foundation.TrackedMemory::Value() Microsoft.iOS.dll:System.IntPtr ObjCRuntime.BlockCollector::block Microsoft.iOS.dll:System.IntPtr ObjCRuntime.Libraries/CoreFoundation::Handle Microsoft.iOS.dll:System.IntPtr ObjCRuntime.NativeHandle::handle @@ -845,9 +848,10 @@ Microsoft.iOS.dll:System.Object Foundation.NSObject/NSObject_Disposer::lock_obj Microsoft.iOS.dll:System.Object ObjCRuntime.Runtime::lock_obj Microsoft.iOS.dll:System.Reflection.Assembly Foundation.NSObject::PlatformAssembly Microsoft.iOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::data_table +Microsoft.iOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 Foundation.NSObject::super_map Microsoft.iOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Runtime::block_lifetime_table Microsoft.iOS.dll:System.Runtime.CompilerServices.ConditionalWeakTable`2 ObjCRuntime.Class::assembly_to_name -Microsoft.iOS.dll:System.Runtime.InteropServices.GCHandle Foundation.NSObjectDataHandle::handle +Microsoft.iOS.dll:System.Runtime.InteropServices.GCHandle Foundation.TrackedMemory::handle Microsoft.iOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::height Microsoft.iOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::width Microsoft.iOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::x diff --git a/tests/framework-test/FrameworkTests.cs b/tests/framework-test/FrameworkTests.cs index da279d818e21..6092954415c4 100644 --- a/tests/framework-test/FrameworkTests.cs +++ b/tests/framework-test/FrameworkTests.cs @@ -19,10 +19,10 @@ public class FrameworkTests { [Test] public void CFunction () { - Assert.AreEqual (42, CFunctions.theUltimateAnswer (), "a"); + Assert.That (CFunctions.theUltimateAnswer (), Is.EqualTo (42), "a"); #if !__MACOS__ - Assert.AreEqual (42, CFunctions.object_theUltimateAnswer (), "object"); - Assert.AreEqual (42, CFunctions.ar_theUltimateAnswer (), "ar"); + Assert.That (CFunctions.object_theUltimateAnswer (), Is.EqualTo (42), "object"); + Assert.That (CFunctions.ar_theUltimateAnswer (), Is.EqualTo (42), "ar"); #endif } @@ -30,7 +30,7 @@ public void CFunction () public void ObjCClass () { using (var obj = new FrameworkTest ()) { - Assert.AreEqual (42, obj.Func (), "a"); + Assert.That (obj.Func (), Is.EqualTo (42), "a"); } } } diff --git a/tests/fsharp/FSharpTests.fs b/tests/fsharp/FSharpTests.fs index ed4c75bb2031..5e05fcec9dc8 100644 --- a/tests/fsharp/FSharpTests.fs +++ b/tests/fsharp/FSharpTests.fs @@ -24,4 +24,4 @@ type FSharpTest () = let e = 5555 let pr = sprintf "%d %d %d %d %d" a b c d e - Assert.AreEqual ("1111 2222 3333 4444 5555", pr) + Assert.That (pr, Is.EqualTo ("1111 2222 3333 4444 5555")) diff --git a/tests/interdependent-binding-projects/Main.cs b/tests/interdependent-binding-projects/Main.cs index 2c08bd2dc725..892a12493f39 100644 --- a/tests/interdependent-binding-projects/Main.cs +++ b/tests/interdependent-binding-projects/Main.cs @@ -15,6 +15,6 @@ static partial void AddTestAssembliesImpl (HashSet assemblies) public class LoaderTest { public void TestAssemblyCount () { - Assert.AreEqual (3, TestLoader.GetTestAssemblies ().Count (), "Test assembly count"); + Assert.That (TestLoader.GetTestAssemblies ().Count (), Is.EqualTo (3), "Test assembly count"); } } diff --git a/tests/linker/link all/dotnet/shared.csproj b/tests/linker/link all/dotnet/shared.csproj index f11e80546aac..6b75ec2a2d4e 100644 --- a/tests/linker/link all/dotnet/shared.csproj +++ b/tests/linker/link all/dotnet/shared.csproj @@ -86,4 +86,10 @@ + + + + + + diff --git a/tests/linker/trimmode link/dotnet/shared.csproj b/tests/linker/trimmode link/dotnet/shared.csproj index 525978b17599..48401810a36d 100644 --- a/tests/linker/trimmode link/dotnet/shared.csproj +++ b/tests/linker/trimmode link/dotnet/shared.csproj @@ -88,4 +88,10 @@ + + + + + + diff --git a/tests/monotouch-test/System.Net.Http/NSUrlSessionHandlerTest.cs b/tests/monotouch-test/System.Net.Http/NSUrlSessionHandlerTest.cs index 86c0b0efb8b3..f8bf44a1035c 100644 --- a/tests/monotouch-test/System.Net.Http/NSUrlSessionHandlerTest.cs +++ b/tests/monotouch-test/System.Net.Http/NSUrlSessionHandlerTest.cs @@ -3,7 +3,11 @@ // using System; +using System.Net; using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading; using System.Threading.Tasks; using Foundation; using NUnit.Framework; @@ -216,5 +220,107 @@ void IgnoreIfExceptionDueToBackgroundServiceInUseByAnotherProcess (Exception? e) Assert.Ignore ("The background service is in use by another process."); } + + // https://github.com/dotnet/macios/issues/25485 + [Test] + public void BasicAuthWorksWhenBearerIsAdvertisedFirst () + { + if (!HttpListener.IsSupported) { + Assert.Inconclusive ("HttpListener is not supported"); + } + + const string username = "admin"; + const string password = "secret"; + var expectedBasicValue = Convert.ToBase64String (Encoding.UTF8.GetBytes ($"{username}:{password}")); + + var serverReady = new SemaphoreSlim (0, 1); + + var httpListener = StartListenerOnAvailablePort (out var listeningPort); + if (httpListener is null) { + Assert.Inconclusive ("Could not find an available port for the test server."); + return; + } + + var serverTask = Task.Run (async () => { + serverReady.Release (); + try { + while (httpListener.IsListening) { + var context = await httpListener.GetContextAsync ().ConfigureAwait (false); + var request = context.Request; + var response = context.Response; + + var authHeader = request.Headers ["Authorization"]; + if (authHeader is not null && authHeader == $"Basic {expectedBasicValue}") { + // Authenticated - return success + response.StatusCode = 200; + var body = Encoding.UTF8.GetBytes ("authenticated"); + response.ContentLength64 = body.Length; + response.OutputStream.Write (body, 0, body.Length); + } else { + // Return 401 with Bearer first, then Basic + response.StatusCode = 401; + response.AddHeader ("WWW-Authenticate", "Bearer realm=\"test\", charset=\"UTF-8\""); + response.AppendHeader ("WWW-Authenticate", "Basic realm=\"test\", charset=\"UTF-8\""); + } + response.Close (); + } + } catch (ObjectDisposedException) { + // listener was stopped + } catch (HttpListenerException) { + // listener was stopped + } + }); + + HttpStatusCode? statusCode = null; + string responseBody = null; + + try { + var done = TestRuntime.TryRunAsync (TimeSpan.FromSeconds (30), async () => { + await serverReady.WaitAsync ().ConfigureAwait (false); + + using var handler = new NSUrlSessionHandler (); + handler.Credentials = new NetworkCredential (username, password); + using var client = new HttpClient (handler); + using var request = new HttpRequestMessage (HttpMethod.Get, $"http://localhost:{listeningPort}/test"); + var response = await client.SendAsync (request).ConfigureAwait (false); + statusCode = response.StatusCode; + responseBody = await response.Content.ReadAsStringAsync ().ConfigureAwait (false); + }, out var ex); + + Assert.That (done, Is.True, "Request timed out"); + Assert.That (ex, Is.Null, $"Exception: {ex}"); + Assert.That (statusCode, Is.EqualTo (HttpStatusCode.OK), "Expected 200 OK after Basic auth negotiation"); + Assert.That (responseBody, Is.EqualTo ("authenticated"), "Response body"); + + if (serverTask.IsFaulted) + Assert.Fail ($"Server task failed: {serverTask.Exception}"); + } finally { + httpListener.Stop (); + httpListener.Close (); + } + } + + static HttpListener? StartListenerOnAvailablePort (out int listeningPort) + { + // IANA suggested range for dynamic or private ports + const int MinPort = 49215; + const int MaxPort = 65535; + + for (var port = MinPort; port < MaxPort; port++) { + var listener = new HttpListener (); + listener.Prefixes.Add ($"http://*:{port}/"); + try { + listener.Start (); + listeningPort = port; + return listener; + } catch { + // port in use, try next + listener.Close (); + } + } + + listeningPort = -1; + return null; + } } } diff --git a/tests/monotouch-test/dotnet/shared.csproj b/tests/monotouch-test/dotnet/shared.csproj index 52b2396eff16..989a89db0bef 100644 --- a/tests/monotouch-test/dotnet/shared.csproj +++ b/tests/monotouch-test/dotnet/shared.csproj @@ -54,6 +54,10 @@ + + + + diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/AssemblySetup.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/AssemblySetup.cs index db3cb3520b67..5059aab86236 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/AssemblySetup.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/AssemblySetup.cs @@ -17,7 +17,7 @@ public void AssemblyInitialization () const string msbuild_exe_path = "/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/msbuild/15.0/bin/MSBuild.dll"; if (is_in_vsmac) { var env = new Dictionary { - { "MD_APPLE_SDK_ROOT", Path.GetDirectoryName (Path.GetDirectoryName (Configuration.xcode_root)) ?? string.Empty }, + { "DEVELOPER_DIR", Path.GetDirectoryName (Path.GetDirectoryName (Configuration.xcode_root)) ?? string.Empty }, { "MSBUILD_EXE_PATH", msbuild_exe_path }, }; diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ACToolTaskTest.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ACToolTaskTest.cs index f0f790709c06..e41ff90d614e 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ACToolTaskTest.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ACToolTaskTest.cs @@ -22,9 +22,9 @@ ACTool CreateACToolTask (ApplePlatform platform, string projectDir, out string i intermediateOutputPath = Cache.CreateTemporaryDirectory (); - var sdk = Sdks.GetAppleSdk (platform); + var task = CreateTask (); + var version = AppleSdkVersion.UseDefault.ToString (); - var root = sdk.GetSdkPath (version, false); string sdkPlatform; var uiDeviceFamily = ""; @@ -47,7 +47,6 @@ ACTool CreateACToolTask (ApplePlatform platform, string projectDir, out string i throw new NotImplementedException (platform.ToString ()); } - var task = CreateTask (); task.ImageAssets = imageAssets .Select (v => { var spl = v.Split ('|'); diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CompileAppManifestTaskTests.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CompileAppManifestTaskTests.cs index 963fc4e4ad83..e07a1d80c94d 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CompileAppManifestTaskTests.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CompileAppManifestTaskTests.cs @@ -20,11 +20,11 @@ CompileAppManifest CreateTask (string? tmpdir = null, ApplePlatform platform = A var task = CreateTask (); task.AppBundleName = "AppBundleName"; task.CompiledAppManifest = new TaskItem (Path.Combine (tmpdir, "TemporaryAppManifest.plist")); - task.DefaultSdkVersion = Sdks.GetAppleSdk (platform).GetInstalledSdkVersions (false).First ().ToString ()!; task.MinSupportedOSPlatformVersion = "10.0"; task.SupportedOSPlatformVersion = "15.0"; task.SdkVersion = task.DefaultSdkVersion ?? string.Empty; task.TargetFrameworkMoniker = TargetFramework.GetTargetFramework (platform).ToString (); + task.DefaultSdkVersion = task.CurrentSdk.GetInstalledSdkVersions (false).First ().ToString ()!; return task; } diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_Core.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_Core.cs index c98886bb4f40..f6b0181548aa 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_Core.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_Core.cs @@ -46,6 +46,7 @@ protected virtual void ConfigureTask () Task.MinSupportedOSPlatformVersion = "10.0"; Task.SupportedOSPlatformVersion = "15.0"; Task.SdkVersion = "10.0"; + Task.TargetFrameworkMoniker = TargetFramework.GetTargetFramework (Platform).ToString (); Plist = new PDictionary (); Plist ["CFBundleDisplayName"] = displayName; diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_iOS.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_iOS.cs index 144e00166d4f..eec87ffd32f5 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_iOS.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_iOS.cs @@ -15,7 +15,7 @@ protected override void ConfigureTask () Configuration.IgnoreIfIgnoredPlatform (ApplePlatform.iOS); base.ConfigureTask (); - Task.DefaultSdkVersion = Sdks.IOS.GetClosestInstalledSdk (AppleSdkVersion.V6_1, true).ToString (); + Task.DefaultSdkVersion = Task.CurrentSdk.GetClosestInstalledSdk (AppleSdkVersion.V6_1, true).ToString () ?? ""; Task.TargetFrameworkMoniker = TargetFramework.DotNet_iOS_String; Task.TargetArchitectures = "ARM64"; } diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_tvOS.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_tvOS.cs index b77904722891..06ab59fadfbe 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_tvOS.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_tvOS.cs @@ -14,7 +14,7 @@ protected override void ConfigureTask () Configuration.IgnoreIfIgnoredPlatform (ApplePlatform.TVOS); base.ConfigureTask (); - Task.DefaultSdkVersion = Sdks.TVOS.GetClosestInstalledSdk (AppleSdkVersion.V9_0, true).ToString (); + Task.DefaultSdkVersion = Task.CurrentSdk.GetClosestInstalledSdk (AppleSdkVersion.V9_0, true).ToString () ?? ""; Task.TargetFrameworkMoniker = TargetFramework.DotNet_tvOS_String; } } diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/IBToolTaskTests.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/IBToolTaskTests.cs index 54819e3ef1cf..2b66ae4a5f93 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/IBToolTaskTests.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/IBToolTaskTests.cs @@ -18,10 +18,10 @@ namespace Xamarin.MacDev.Tasks { public class IBToolTaskTests : TestBase { IBTool CreateIBToolTask (ApplePlatform framework, string projectDir, string intermediateOutputPath) { + var task = CreateTask (); + var interfaceDefinitions = new List (); - var sdk = Sdks.GetSdk (framework); - var version = AppleSdkVersion.GetDefault (sdk, false); - var root = sdk.GetSdkPath (version, false); + var version = AppleSdkVersion.UseDefault.ToString (); string platform; switch (framework) { @@ -39,7 +39,6 @@ IBTool CreateIBToolTask (ApplePlatform framework, string projectDir, string inte foreach (var item in Directory.EnumerateFiles (projectDir, "*.xib", SearchOption.AllDirectories)) interfaceDefinitions.Add (new TaskItem (item)); - var task = CreateTask (); task.InterfaceDefinitions = interfaceDefinitions.ToArray (); task.IntermediateOutputPath = intermediateOutputPath; task.MinimumOSVersion = PDictionary.OpenFile (Path.Combine (projectDir, "Info.plist")).GetMinimumOSVersion (); @@ -48,8 +47,8 @@ IBTool CreateIBToolTask (ApplePlatform framework, string projectDir, string inte task.SdkDevPath = Configuration.xcode_root; task.SdkPlatform = platform; task.SdkVersion = version.ToString (); - task.SdkRoot = root; task.TargetFrameworkMoniker = TargetFramework.DotNet_iOS_String; + task.SdkRoot = task.CurrentSdk.GetSdkPath (version, false); return task; } @@ -62,7 +61,7 @@ public void TestBasicIBToolFunctionality () var ibtool = CreateIBToolTask (ApplePlatform.iOS, srcdir, tmp); var bundleResources = new HashSet (); - Assert.That (ibtool.Execute (), Is.True, "Execution of IBTool task failed."); + ExecuteTask (ibtool); foreach (var bundleResource in ibtool.BundleResources) { Assert.That (File.Exists (bundleResource.ItemSpec), Is.True, $"File does not exist: {bundleResource.ItemSpec}"); @@ -104,7 +103,7 @@ public void TestAdvancedIBToolFunctionality () ibtool.EnableOnDemandResources = true; - Assert.That (ibtool.Execute (), Is.True, "Execution of IBTool task failed."); + ExecuteTask (ibtool); foreach (var bundleResource in ibtool.BundleResources) { var bundleName = bundleResource.GetMetadata ("LogicalName"); @@ -179,7 +178,7 @@ void TestGenericAndDeviceSpecificXibsGeneric (params string [] fileNames) ibtool.EnableOnDemandResources = true; - Assert.That (ibtool.Execute (), Is.True, "Execution of IBTool task failed."); + ExecuteTask (ibtool); foreach (var bundleResource in ibtool.BundleResources) { var bundleName = bundleResource.GetMetadata ("LogicalName"); diff --git a/tests/package-mac-tests.sh b/tests/package-mac-tests.sh index ce02bb0d67eb..0b8dc92d6dab 100755 --- a/tests/package-mac-tests.sh +++ b/tests/package-mac-tests.sh @@ -19,7 +19,7 @@ cat test.config INCLUDE_MAC=$(grep ^INCLUDE_MAC= test.config | sed 's/.*=//') INCLUDE_MACCATALYST=$(grep ^INCLUDE_MACCATALYST= test.config | sed 's/.*=//') XCODE_DEVELOPER_ROOT=$(grep ^XCODE_DEVELOPER_ROOT= test.config | sed 's/.*=//') -export MD_APPLE_SDK_ROOT="$(dirname "$(dirname "$XCODE_DEVELOPER_ROOT")")" +export DEVELOPER_DIR="$(dirname "$(dirname "$XCODE_DEVELOPER_ROOT")")" export RootTestsDirectory="$(pwd)" make diff --git a/tests/test-libraries/testgenerator.cs b/tests/test-libraries/testgenerator.cs index b50e7b191a8c..c118503a9a17 100644 --- a/tests/test-libraries/testgenerator.cs +++ b/tests/test-libraries/testgenerator.cs @@ -953,7 +953,7 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t\tusing (var tc = new ObjCRegistrarTest ()) {"); w.AppendLine ($"\t\t\t\tvar s = tc.PS{s};"); for (int i = 0; i < s.Length; i++) - w.AppendLine ($"\t\t\t\tAssert.AreEqual (0, s.x{i}, \"pre-#{i}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (s.x{i}, Is.EqualTo (0), \"pre-#{i}\");"); w.Append ($"\t\t\t\tvar k = new S{s} () {{ "); for (int i = 0; i < s.Length; i++) w.Append ($"x{i} = ").Append (GetValue (s [i], i)).Append (", "); @@ -962,7 +962,7 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ($"\t\t\t\ttc.PS{s} = k;"); w.AppendLine ($"\t\t\t\ts = tc.PS{s};"); for (int i = 0; i < s.Length; i++) - w.AppendLine ($"\t\t\t\tAssert.AreEqual (k.x{i}, s.x{i}, \"post-#{i}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (s.x{i}, Is.EqualTo (k.x{i}), \"post-#{i}\");"); w.AppendLine (); w.Append ($"\t\t\t\tvar v = new S{s} () {{ "); @@ -975,7 +975,7 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ($"\t\t\t\ttc.SetProperty{s} (v);"); w.AppendLine ($"\t\t\t\ts = tc.PS{s};"); for (int i = 0; i < s.Length; i++) - w.AppendLine ($"\t\t\t\tAssert.AreEqual (v.x{i}, s.x{i}, \"set-#{i}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (s.x{i}, Is.EqualTo (v.x{i}), \"set-#{i}\");"); w.AppendLine ("\t\t\t}"); w.AppendLine ("\t\t}"); @@ -1066,32 +1066,32 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new ObjCRegistrarTest ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}Number, \"initial null property\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}NumberNullable, \"initial nullable null property\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.Get{v.Managed}NumberNullable (), \"initial null method\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Number, Is.Null, \"initial null property\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}NumberNullable, Is.Null, \"initial nullable null property\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}NumberNullable (), Is.Null, \"initial null method\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\t{v.Managed}? value = default ({v.Managed});"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}NumberNonNullable (value.Value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.P{v.Managed}NumberNullable, \"nullable property after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.P{v.Managed}NumberNonNullable, \"non-nullable property after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.Get{v.Managed}NumberNullable (), \"nullable get method after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.Get{v.Managed}NumberNonNullable (), \"non-nullable get method after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}NumberNullable, Is.EqualTo (value), \"nullable property after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}NumberNonNullable, Is.EqualTo (value.Value), \"non-nullable property after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}NumberNullable (), Is.EqualTo (value), \"nullable get method after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}NumberNonNullable (), Is.EqualTo (value.Value), \"non-nullable get method after setting default value\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}NumberNonNullable (value.Value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.P{v.Managed}NumberNullable, \"nullable property after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.P{v.Managed}NumberNonNullable, \"non-nullable property after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.Get{v.Managed}NumberNullable (), \"nullable get method after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.Get{v.Managed}NumberNonNullable (), \"non-nullable get method after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}NumberNullable, Is.EqualTo (value), \"nullable property after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}NumberNonNullable, Is.EqualTo (value.Value), \"non-nullable property after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}NumberNullable (), Is.EqualTo (value), \"nullable get method after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}NumberNonNullable (), Is.EqualTo (value.Value), \"non-nullable get method after setting custom value\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = null;"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}NumberNullable (value);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}Number, \"null property after setting null value\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}NumberNullable, \"nullable null property after setting null value\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.Get{v.Managed}NumberNullable (), \"null method after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Number, Is.Null, \"null property after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}NumberNullable, Is.Null, \"nullable null property after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}NumberNullable (), Is.Null, \"null method after setting null value\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); w.AppendLine (); @@ -1102,43 +1102,43 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new BindAsTestClassGenerated ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Number, \"initial null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Number, Is.Null, \"initial null\");"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}NumberNullable:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Number, \"null after setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Number, Is.Null, \"null after setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Number = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}NumberNullable:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Number, \"null after re-setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Number, Is.Null, \"null after re-setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvar value = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tusing (var input = new NSNumber ({v.ToNSNumberCastExpression}value))"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}NumberNullable:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.{v.Managed}Number, \"after setting A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Number, Is.EqualTo (value), \"after setting A\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Number = null;"); w.AppendLine ($"\t\t\t\tusing (var input = new NSNumber ({v.ToNSNumberCastExpression}value))"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}NumberNonNullable:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.{v.Managed}Number.Value, \"after setting B\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Number.Value, Is.EqualTo (value), \"after setting B\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Number = null;"); w.AppendLine ($"\t\t\t\tvar number = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}NumberNullable\")));"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (number, \"null from getter A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (number, Is.Null, \"null from getter A\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Number = value;"); w.AppendLine ($"\t\t\t\tnumber = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}NumberNullable\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, {v.FromNSNumberCastExpression}number{v.Map}, \"getter B\");"); + w.AppendLine ($"\t\t\t\tAssert.That ({v.FromNSNumberCastExpression}number{v.Map}, Is.EqualTo (value), \"getter B\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Number = value;"); w.AppendLine ($"\t\t\t\tnumber = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}NumberNonNullable\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, {v.FromNSNumberCastExpression}number{v.Map}, \"getter C\");"); + w.AppendLine ($"\t\t\t\tAssert.That ({v.FromNSNumberCastExpression}number{v.Map}, Is.EqualTo (value), \"getter C\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); @@ -1148,28 +1148,28 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new ObjCRegistrarTest ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}Array, \"initial null property\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.Get{v.Managed}Array (), \"initial null method\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array, Is.Null, \"initial null property\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array (), Is.Null, \"initial null method\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\t{v.Managed}[] value = null;"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}Array (value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.P{v.Managed}Array, \"nullable property after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.Get{v.Managed}Array (), \"nullable get method after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array, Is.EqualTo (value), \"nullable property after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array (), Is.EqualTo (value), \"nullable get method after setting default value\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}Array (value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (1, obj.P{v.Managed}Array.Length, \"nullable property after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (1, obj.Get{v.Managed}Array ().Length, \"nullable get method after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.P{v.Managed}Array [0], \"nullable property after setting custom value element\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.Get{v.Managed}Array () [0], \"nullable get method after setting custom value element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array.Length, Is.EqualTo (1), \"nullable property after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array ().Length, Is.EqualTo (1), \"nullable get method after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array [0], Is.EqualTo (value [0]), \"nullable property after setting custom value element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array () [0], Is.EqualTo (value [0]), \"nullable get method after setting custom value element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = null;"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}Array (value);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}Array, \"null property after setting null value\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.Get{v.Managed}Array (), \"null method after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array, Is.Null, \"null property after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array (), Is.Null, \"null method after setting null value\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); w.AppendLine (); @@ -1180,40 +1180,40 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new BindAsTestClassGenerated ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Array, \"initial null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array, Is.Null, \"initial null\");"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}Array:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Array, \"null after setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array, Is.Null, \"null after setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Array = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}Array:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Array, \"null after re-setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array, Is.Null, \"null after re-setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvar value = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tusing (var input = NSArray.FromNSObjects<{v.Managed}> ((v) => new NSNumber ({v.ToNSNumberCastExpression}v), value))"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}Array:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Length, obj.{v.Managed}Array.Length, \"after setting A\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.{v.Managed}Array [0], \"after setting A element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array.Length, Is.EqualTo (value.Length), \"after setting A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array [0], Is.EqualTo (value [0]), \"after setting A element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Array = null;"); w.AppendLine ($"\t\t\t\tusing (var input = NSArray.FromNSObjects<{v.Managed}> ((v) => new NSNumber ({v.ToNSNumberCastExpression}v), value))"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}Array:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Length, obj.{v.Managed}Array.Length, \"after setting B\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.{v.Managed}Array [0], \"after setting B element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array.Length, Is.EqualTo (value.Length), \"after setting B\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array [0], Is.EqualTo (value [0]), \"after setting B element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Array = null;"); w.AppendLine ($"\t\t\t\tvar array = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}Array\")));"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (array, \"null from getter A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (array, Is.Null, \"null from getter A\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Array = value;"); w.AppendLine ($"\t\t\t\tarray = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}Array\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual ((nuint) value.Length, array.Count, \"getter B\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], {v.FromNSNumberCastExpression}array.GetItem (0){v.Map}, \"getter B element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (array.Count, Is.EqualTo ((nuint) value.Length), \"getter B\");"); + w.AppendLine ($"\t\t\t\tAssert.That ({v.FromNSNumberCastExpression}array.GetItem (0){v.Map}, Is.EqualTo (value [0]), \"getter B element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t}}"); @@ -1236,32 +1236,32 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new ObjCRegistrarTest ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}Value, \"initial null property\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}ValueNullable, \"initial nullable null property\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.Get{v.Managed}ValueNullable (), \"initial null method\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Value, Is.Null, \"initial null property\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}ValueNullable, Is.Null, \"initial nullable null property\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}ValueNullable (), Is.Null, \"initial null method\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\t{v.Managed}? value = default ({v.Managed});"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}ValueNonNullable (value.Value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.P{v.Managed}ValueNullable, \"nullable property after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.P{v.Managed}ValueNonNullable, \"non-nullable property after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.Get{v.Managed}ValueNullable (), \"nullable get method after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.Get{v.Managed}ValueNonNullable (), \"non-nullable get method after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}ValueNullable, Is.EqualTo (value), \"nullable property after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}ValueNonNullable, Is.EqualTo (value.Value), \"non-nullable property after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}ValueNullable (), Is.EqualTo (value), \"nullable get method after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}ValueNonNullable (), Is.EqualTo (value.Value), \"non-nullable get method after setting default value\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}ValueNonNullable (value.Value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.P{v.Managed}ValueNullable, \"nullable property after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.P{v.Managed}ValueNonNullable, \"non-nullable property after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.Get{v.Managed}ValueNullable (), \"nullable get method after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.Get{v.Managed}ValueNonNullable (), \"non-nullable get method after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}ValueNullable, Is.EqualTo (value), \"nullable property after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}ValueNonNullable, Is.EqualTo (value.Value), \"non-nullable property after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}ValueNullable (), Is.EqualTo (value), \"nullable get method after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}ValueNonNullable (), Is.EqualTo (value.Value), \"non-nullable get method after setting custom value\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = null;"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}ValueNullable (value);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}Value, \"null property after setting null value\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}ValueNullable, \"nullable null property after setting null value\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.Get{v.Managed}ValueNullable (), \"null method after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Value, Is.Null, \"null property after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}ValueNullable, Is.Null, \"nullable null property after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}ValueNullable (), Is.Null, \"null method after setting null value\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); w.AppendLine (); @@ -1272,43 +1272,43 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new BindAsTestClassGenerated ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Value, \"initial null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Value, Is.Null, \"initial null\");"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}ValueNullable:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Value, \"null after setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Value, Is.Null, \"null after setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Value = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}ValueNullable:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Value, \"null after re-setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Value, Is.Null, \"null after re-setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvar value = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tusing (var input = NSValue.{v.MapFrom} (value))"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}ValueNullable:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.{v.Managed}Value, \"after setting A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Value, Is.EqualTo (value), \"after setting A\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Value = null;"); w.AppendLine ($"\t\t\t\tusing (var input = NSValue.{v.MapFrom} (value))"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}ValueNonNullable:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.{v.Managed}Value, \"after setting B\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Value, Is.EqualTo (value), \"after setting B\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Value = null;"); w.AppendLine ($"\t\t\t\tvar Value = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}ValueNullable\")));"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (Value, \"null from getter A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (Value, Is.Null, \"null from getter A\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Value = value;"); w.AppendLine ($"\t\t\t\tValue = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}ValueNullable\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, Value{v.Map}, \"getter B\");"); + w.AppendLine ($"\t\t\t\tAssert.That (Value{v.Map}, Is.EqualTo (value), \"getter B\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Value = value;"); w.AppendLine ($"\t\t\t\tValue = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}ValueNonNullable\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, Value{v.Map}, \"getter C\");"); + w.AppendLine ($"\t\t\t\tAssert.That (Value{v.Map}, Is.EqualTo (value), \"getter C\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); @@ -1318,28 +1318,28 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new ObjCRegistrarTest ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}Array, \"initial null property\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.Get{v.Managed}Array (), \"initial null method\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array, Is.Null, \"initial null property\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array (), Is.Null, \"initial null method\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\t{v.Managed}[] value = null;"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}Array (value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.P{v.Managed}Array, \"nullable property after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.Get{v.Managed}Array (), \"nullable get method after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array, Is.EqualTo (value), \"nullable property after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array (), Is.EqualTo (value), \"nullable get method after setting default value\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}Array (value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (1, obj.P{v.Managed}Array.Length, \"nullable property after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (1, obj.Get{v.Managed}Array ().Length, \"nullable get method after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.P{v.Managed}Array [0], \"nullable property after setting custom value element\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.Get{v.Managed}Array () [0], \"nullable get method after setting custom value element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array.Length, Is.EqualTo (1), \"nullable property after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array ().Length, Is.EqualTo (1), \"nullable get method after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array [0], Is.EqualTo (value [0]), \"nullable property after setting custom value element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array () [0], Is.EqualTo (value [0]), \"nullable get method after setting custom value element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = null;"); w.AppendLine ($"\t\t\t\tobj.Set{v.Managed}Array (value);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.P{v.Managed}Array, \"null property after setting null value\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.Get{v.Managed}Array (), \"null method after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.P{v.Managed}Array, Is.Null, \"null property after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.Get{v.Managed}Array (), Is.Null, \"null method after setting null value\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); w.AppendLine (); @@ -1350,40 +1350,40 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new BindAsTestClassGenerated ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Array, \"initial null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array, Is.Null, \"initial null\");"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}Array:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Array, \"null after setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array, Is.Null, \"null after setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Array = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}Array:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.{v.Managed}Array, \"null after re-setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array, Is.Null, \"null after re-setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvar value = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tusing (var input = NSArray.FromNSObjects<{v.Managed}> ((v) => NSValue.{v.MapFrom} (v), value))"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}Array:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Length, obj.{v.Managed}Array.Length, \"after setting A\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.{v.Managed}Array [0], \"after setting A element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array.Length, Is.EqualTo (value.Length), \"after setting A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array [0], Is.EqualTo (value [0]), \"after setting A element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Array = null;"); w.AppendLine ($"\t\t\t\tusing (var input = NSArray.FromNSObjects<{v.Managed}> ((v) => NSValue.{v.MapFrom} (v), value))"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"set{v.Managed}Array:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Length, obj.{v.Managed}Array.Length, \"after setting B\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.{v.Managed}Array [0], \"after setting B element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array.Length, Is.EqualTo (value.Length), \"after setting B\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.{v.Managed}Array [0], Is.EqualTo (value [0]), \"after setting B element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Array = null;"); w.AppendLine ($"\t\t\t\tvar array = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}Array\")));"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (array, \"null from getter A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (array, Is.Null, \"null from getter A\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tobj.{v.Managed}Array = value;"); w.AppendLine ($"\t\t\t\tarray = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"get{v.Managed}Array\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual ((nuint) value.Length, array.Count, \"getter B\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], array.GetItem (0){v.Map}, \"getter B element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (array.Count, Is.EqualTo ((nuint) value.Length), \"getter B\");"); + w.AppendLine ($"\t\t\t\tAssert.That (array.GetItem (0){v.Map}, Is.EqualTo (value [0]), \"getter B element\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); w.AppendLine (); @@ -1406,28 +1406,28 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ($"\t\t\tusing (var obj = new ObjCRegistrarTest ()) {{"); w.AppendLine ($"\t\t\t\tAssert.Throws (() => {{ Console.WriteLine (obj.PSmart{v.Managed}Property); }}, \"initial zero property\");"); w.AppendLine ($"\t\t\t\tAssert.Throws (() => {{ Console.WriteLine (obj.GetSmart{v.Managed}Value ()); }}, \"initial zero method\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.GetSmartNullable{v.Managed}Value (), \"initial null method\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmartNullable{v.Managed}Value (), Is.Null, \"initial null method\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\t{v.Managed}? value = default ({v.Managed});"); w.AppendLine ($"\t\t\t\tobj.SetSmartNullable{v.Managed}Value (value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.PSmart{v.Managed}Property, \"zero property after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.GetSmart{v.Managed}Value (), \"non-nullable property after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.GetSmartNullable{v.Managed}Value (), \"nullable get method after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Property, Is.EqualTo (value.Value), \"zero property after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmart{v.Managed}Value (), Is.EqualTo (value.Value), \"non-nullable property after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmartNullable{v.Managed}Value (), Is.EqualTo (value), \"nullable get method after setting default value\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tobj.SetSmart{v.Managed}Value (value.Value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.PSmart{v.Managed}Property, \"non-nullable property after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.GetSmartNullable{v.Managed}Value (), \"nullable get method after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Value, obj.GetSmart{v.Managed}Value (), \"non-nullable get method after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Property, Is.EqualTo (value.Value), \"non-nullable property after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmartNullable{v.Managed}Value (), Is.EqualTo (value), \"nullable get method after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmart{v.Managed}Value (), Is.EqualTo (value.Value), \"non-nullable get method after setting custom value\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = null;"); w.AppendLine ($"\t\t\t\tobj.SetSmartNullable{v.Managed}Value (value);"); w.AppendLine ($"\t\t\t\tAssert.Throws (() => {{ Console.WriteLine (obj.PSmart{v.Managed}Property); }}, \"null property after setting null value\");"); w.AppendLine ($"\t\t\t\tAssert.Throws (() => {{ Console.WriteLine (obj.GetSmart{v.Managed}Value ()); }}, \"non-nullable method after setting null value\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.GetSmartNullable{v.Managed}Value (), \"null method after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmartNullable{v.Managed}Value (), Is.Null, \"null method after setting null value\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); w.AppendLine (); @@ -1451,30 +1451,30 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ($"\t\t\t\tvar value = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tusing (var input = value.GetConstant ())"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"setSmartNullable{v.Managed}Value:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.PSmart{v.Managed}Property, \"after setting A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Property, Is.EqualTo (value), \"after setting A\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.PSmart{v.Managed}Property = 0;"); w.AppendLine ($"\t\t\t\tusing (var input = value.GetConstant ())"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"setSmart{v.Managed}Value:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.PSmart{v.Managed}Property, \"after setting B\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Property, Is.EqualTo (value), \"after setting B\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.PSmart{v.Managed}Property = 0;"); w.AppendLine ($"\t\t\t\tvar Value = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"getSmartNullable{v.Managed}Value\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (default ({v.Managed}).GetConstant ().ToString (), Value.ToString (), \"zero from getter A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (Value.ToString (), Is.EqualTo (default ({v.Managed}).GetConstant ().ToString ()), \"zero from getter A\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tobj.PSmart{v.Managed}Property = value;"); w.AppendLine ($"\t\t\t\tValue = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"getSmartNullable{v.Managed}Value\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, {v.Managed}Extensions.GetValue (Value), \"getter B\");"); + w.AppendLine ($"\t\t\t\tAssert.That ({v.Managed}Extensions.GetValue (Value), Is.EqualTo (value), \"getter B\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = {v.ManagedNewExpression};"); w.AppendLine ($"\t\t\t\tobj.PSmart{v.Managed}Property = value;"); w.AppendLine ($"\t\t\t\tValue = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"getSmart{v.Managed}Value\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, {v.Managed}Extensions.GetValue (Value), \"getter C\");"); + w.AppendLine ($"\t\t\t\tAssert.That ({v.Managed}Extensions.GetValue (Value), Is.EqualTo (value), \"getter C\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); @@ -1484,28 +1484,28 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new ObjCRegistrarTest ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.PSmart{v.Managed}Properties, \"initial null property\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.GetSmart{v.Managed}Values (), \"initial null method\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties, Is.Null, \"initial null property\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmart{v.Managed}Values (), Is.Null, \"initial null method\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\t{v.Managed}[] value = null;"); w.AppendLine ($"\t\t\t\tobj.SetSmart{v.Managed}Values (value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.PSmart{v.Managed}Properties, \"nullable property after setting default value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value, obj.GetSmart{v.Managed}Values (), \"nullable get method after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties, Is.EqualTo (value), \"nullable property after setting default value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmart{v.Managed}Values (), Is.EqualTo (value), \"nullable get method after setting default value\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tobj.SetSmart{v.Managed}Values (value);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (1, obj.PSmart{v.Managed}Properties.Length, \"nullable property after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (1, obj.GetSmart{v.Managed}Values ().Length, \"nullable get method after setting custom value\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.PSmart{v.Managed}Properties [0], \"nullable property after setting custom value element\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.GetSmart{v.Managed}Values () [0], \"nullable get method after setting custom value element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties.Length, Is.EqualTo (1), \"nullable property after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmart{v.Managed}Values ().Length, Is.EqualTo (1), \"nullable get method after setting custom value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties [0], Is.EqualTo (value [0]), \"nullable property after setting custom value element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmart{v.Managed}Values () [0], Is.EqualTo (value [0]), \"nullable get method after setting custom value element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = null;"); w.AppendLine ($"\t\t\t\tobj.SetSmart{v.Managed}Values (value);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.PSmart{v.Managed}Properties, \"null property after setting null value\");"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.GetSmart{v.Managed}Values (), \"null method after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties, Is.Null, \"null property after setting null value\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.GetSmart{v.Managed}Values (), Is.Null, \"null method after setting null value\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); w.AppendLine (); @@ -1516,40 +1516,40 @@ public partial class RegistrarTestGenerated {"); w.AppendLine ("\t\t{"); WriteAsserts (w, v); w.AppendLine ($"\t\t\tusing (var obj = new BindAsTestClassGenerated ()) {{"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.PSmart{v.Managed}Properties, \"initial null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties, Is.Null, \"initial null\");"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"setSmart{v.Managed}Values:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.PSmart{v.Managed}Properties, \"null after setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties, Is.Null, \"null after setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.PSmart{v.Managed}Properties = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"setSmart{v.Managed}Values:\"), IntPtr.Zero);"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (obj.PSmart{v.Managed}Properties, \"null after re-setting null\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties, Is.Null, \"null after re-setting null\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvar value = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tusing (var input = NSArray.FromNSObjects<{v.Managed}> ((v) => v.GetConstant (), value))"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"setSmart{v.Managed}Values:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Length, obj.PSmart{v.Managed}Properties.Length, \"after setting A\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.PSmart{v.Managed}Properties [0], \"after setting A element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties.Length, Is.EqualTo (value.Length), \"after setting A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties [0], Is.EqualTo (value [0]), \"after setting A element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.PSmart{v.Managed}Properties = null;"); w.AppendLine ($"\t\t\t\tusing (var input = NSArray.FromNSObjects<{v.Managed}> ((v) => v.GetConstant (), value))"); w.AppendLine ($"\t\t\t\t\tMessaging.void_objc_msgSend_IntPtr (obj.Handle, Selector.GetHandle (\"setSmart{v.Managed}Values:\"), input.Handle);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value.Length, obj.PSmart{v.Managed}Properties.Length, \"after setting B\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], obj.PSmart{v.Managed}Properties [0], \"after setting B element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties.Length, Is.EqualTo (value.Length), \"after setting B\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.PSmart{v.Managed}Properties [0], Is.EqualTo (value [0]), \"after setting B element\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tobj.PSmart{v.Managed}Properties = null;"); w.AppendLine ($"\t\t\t\tvar array = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"getSmart{v.Managed}Values\")));"); - w.AppendLine ($"\t\t\t\tAssert.IsNull (array, \"null from getter A\");"); + w.AppendLine ($"\t\t\t\tAssert.That (array, Is.Null, \"null from getter A\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\tvalue = new {v.Managed} [] {{ {v.ManagedNewExpression} }};"); w.AppendLine ($"\t\t\t\tobj.PSmart{v.Managed}Properties = value;"); w.AppendLine ($"\t\t\t\tarray = Runtime.GetNSObject (Messaging.IntPtr_objc_msgSend (obj.Handle, Selector.GetHandle (\"getSmart{v.Managed}Values\")));"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual ((nuint) value.Length, array.Count, \"getter B\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (value [0], {v.Managed}Extensions.GetValue (array.GetItem (0)), \"getter B element\");"); + w.AppendLine ($"\t\t\t\tAssert.That (array.Count, Is.EqualTo ((nuint) value.Length), \"getter B\");"); + w.AppendLine ($"\t\t\t\tAssert.That ({v.Managed}Extensions.GetValue (array.GetItem (0)), Is.EqualTo (value [0]), \"getter B element\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine ("\t\t}"); w.AppendLine (); @@ -1720,7 +1720,7 @@ public partial class TrampolineTestGenerated {"); w.AppendLine ($"\t\t\t\t\trv = S{s}_objc_msgSend (obj.Handle, new Selector (\"Test_{s}Struct\").Handle);"); w.AppendLine ($"\t\t\t\t}}"); } - w.AppendLine ($"\t\t\t\tAssert.AreEqual (({GenerateNewExpression (s, 1)}).ToString (), rv.ToString (), \"a\");"); + w.AppendLine ($"\t\t\t\tAssert.That (rv.ToString (), Is.EqualTo (({GenerateNewExpression (s, 1)}).ToString ()), \"a\");"); w.AppendLine (); WriteStretConditions (w, s, out never); @@ -1732,7 +1732,7 @@ public partial class TrampolineTestGenerated {"); w.AppendLine ($"\t\t\t\t\trv = S{s}_objc_msgSend (class_ptr, new Selector (\"Test_Static{s}Struct\").Handle);"); w.AppendLine ($"\t\t\t\t}}"); } - w.AppendLine ($"\t\t\t\tAssert.AreEqual (({GenerateNewExpression (s, 2)}).ToString (), rv.ToString (), \"a\");"); + w.AppendLine ($"\t\t\t\tAssert.That (rv.ToString (), Is.EqualTo (({GenerateNewExpression (s, 2)}).ToString ()), \"a\");"); w.AppendLine (); WriteStretConditions (w, s, out never); @@ -1744,7 +1744,7 @@ public partial class TrampolineTestGenerated {"); w.AppendLine ($"\t\t\t\t\trv = S{s}_objc_msgSend (obj.Handle, new Selector (\"Test_{s}StructProperty\").Handle);"); w.AppendLine ($"\t\t\t\t}}"); } - w.AppendLine ($"\t\t\t\tAssert.AreEqual (({GenerateNewExpression (s, 3)}).ToString (), rv.ToString (), \"a\");"); + w.AppendLine ($"\t\t\t\tAssert.That (rv.ToString (), Is.EqualTo (({GenerateNewExpression (s, 3)}).ToString ()), \"a\");"); w.AppendLine (); WriteStretConditions (w, s, out never); @@ -1756,7 +1756,7 @@ public partial class TrampolineTestGenerated {"); w.AppendLine ($"\t\t\t\t\trv = S{s}_objc_msgSend (class_ptr, new Selector (\"Test_Static{s}StructProperty\").Handle);"); w.AppendLine ($"\t\t\t\t}}"); } - w.AppendLine ($"\t\t\t\tAssert.AreEqual (({GenerateNewExpression (s, 4)}).ToString (), rv.ToString (), \"a\");"); + w.AppendLine ($"\t\t\t\tAssert.That (rv.ToString (), Is.EqualTo (({GenerateNewExpression (s, 4)}).ToString ()), \"a\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\trvd = 0;"); @@ -1769,8 +1769,8 @@ public partial class TrampolineTestGenerated {"); w.AppendLine ($"\t\t\t\t\trv = S{s}_objc_msgSend_out_double (obj.Handle, new Selector (\"Test_{s}Struct_out_double:\").Handle, out rvd);"); w.AppendLine ($"\t\t\t\t}}"); } - w.AppendLine ($"\t\t\t\tAssert.AreEqual (({GenerateNewExpression (s, 5)}).ToString (), rv.ToString (), \"a\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (3.14, rvd, \"double out\");"); + w.AppendLine ($"\t\t\t\tAssert.That (rv.ToString (), Is.EqualTo (({GenerateNewExpression (s, 5)}).ToString ()), \"a\");"); + w.AppendLine ($"\t\t\t\tAssert.That (rvd, Is.EqualTo (3.14), \"double out\");"); w.AppendLine (); w.AppendLine ($"\t\t\t\trvf = 0;"); @@ -1783,8 +1783,8 @@ public partial class TrampolineTestGenerated {"); w.AppendLine ($"\t\t\t\t\trv = S{s}_objc_msgSend_out_float (class_ptr, new Selector (\"Test_Static{s}Struct_out_float:\").Handle, out rvf);"); w.AppendLine ($"\t\t\t\t}}"); } - w.AppendLine ($"\t\t\t\tAssert.AreEqual (({GenerateNewExpression (s, 6)}).ToString (), rv.ToString (), \"a\");"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (3.15f, rvf, \"float out\");"); + w.AppendLine ($"\t\t\t\tAssert.That (rv.ToString (), Is.EqualTo (({GenerateNewExpression (s, 6)}).ToString ()), \"a\");"); + w.AppendLine ($"\t\t\t\tAssert.That (rvf, Is.EqualTo (3.15f), \"float out\");"); w.AppendLine (); w.AppendLine ($"\t\t\t}}"); @@ -1793,7 +1793,7 @@ public partial class TrampolineTestGenerated {"); w.AppendLine ($"\t\t\tusing (var obj = new OverrideRegistrarTest ()) {{"); w.AppendLine ($"\t\t\t\tvar structValue = {GenerateNewExpression (s, 7)};"); w.AppendLine ($"\t\t\t\tvoid_objc_msgSend_{s} (obj.Handle, Selector.GetHandle (\"setProperty{s}:\"), structValue);"); - w.AppendLine ($"\t\t\t\tAssert.AreEqual (structValue.ToString (), obj.V{s}.ToString (), \"SetProperty#1\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.V{s}.ToString (), Is.EqualTo (structValue.ToString ()), \"SetProperty#1\");"); w.AppendLine ($"\t\t\t}}"); w.AppendLine (); @@ -1813,9 +1813,9 @@ public partial class TrampolineTestGenerated {"); for (var x = 1; x <= i + 1; x++) { if (x == i) { - w.AppendLine ($"\t\t\t\tAssert.AreEqual (structValue.ToString (), obj.V{s}.ToString (), \"SetProperty#2-S{x}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.V{s}.ToString (), Is.EqualTo (structValue.ToString ()), \"SetProperty#2-S{x}\");"); } else { - w.AppendLine ($"\t\t\t\tAssert.AreEqual ((nint) {x}, obj.ManagedVoidArg{x}, \"SetProperty#2-X{x}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.ManagedVoidArg{x}, Is.EqualTo ((nint) {x}), \"SetProperty#2-X{x}\");"); } } w.AppendLine ($"\t\t\t}}"); @@ -1838,11 +1838,11 @@ public partial class TrampolineTestGenerated {"); for (var x = 1; x <= i + 1; x++) { if (x == 1) { - w.AppendLine ($"\t\t\t\tAssert.AreEqual ((float) {x}, obj.ManagedFloatArg{x}, \"SetProperty#3-X{x}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.ManagedFloatArg{x}, Is.EqualTo ((float) {x}), \"SetProperty#3-X{x}\");"); } else if (x == i) { - w.AppendLine ($"\t\t\t\tAssert.AreEqual (structValue.ToString (), obj.V{s}.ToString (), \"SetProperty#3-S{x}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.V{s}.ToString (), Is.EqualTo (structValue.ToString ()), \"SetProperty#3-S{x}\");"); } else { - w.AppendLine ($"\t\t\t\tAssert.AreEqual ((nint) {x}, obj.ManagedVoidArg{x}, \"SetProperty#3-X{x}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.ManagedVoidArg{x}, Is.EqualTo ((nint) {x}), \"SetProperty#3-X{x}\");"); } } w.AppendLine ($"\t\t\t}}"); @@ -1865,11 +1865,11 @@ public partial class TrampolineTestGenerated {"); for (var x = 1; x <= i + 1; x++) { if (x == 1) { - w.AppendLine ($"\t\t\t\tAssert.AreEqual ((double) {x}, obj.ManagedDoubleArg{x}, \"SetProperty#3-X{x}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.ManagedDoubleArg{x}, Is.EqualTo ((double) {x}), \"SetProperty#3-X{x}\");"); } else if (x == i) { - w.AppendLine ($"\t\t\t\tAssert.AreEqual (structValue.ToString (), obj.V{s}.ToString (), \"SetProperty#3-S{x}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.V{s}.ToString (), Is.EqualTo (structValue.ToString ()), \"SetProperty#3-S{x}\");"); } else { - w.AppendLine ($"\t\t\t\tAssert.AreEqual ((nint) {x}, obj.ManagedVoidArg{x}, \"SetProperty#3-X{x}\");"); + w.AppendLine ($"\t\t\t\tAssert.That (obj.ManagedVoidArg{x}, Is.EqualTo ((nint) {x}), \"SetProperty#3-X{x}\");"); } } w.AppendLine ($"\t\t\t}}"); diff --git a/tests/xcframework-test/XCFrameworkTests.cs b/tests/xcframework-test/XCFrameworkTests.cs index 206951ea19b0..2926ee397ed8 100644 --- a/tests/xcframework-test/XCFrameworkTests.cs +++ b/tests/xcframework-test/XCFrameworkTests.cs @@ -19,14 +19,14 @@ public class FrameworkTests { [Test] public void CFunction () { - Assert.AreEqual (42, CFunctions.theUltimateAnswer (), "a"); + Assert.That (CFunctions.theUltimateAnswer (), Is.EqualTo (42), "a"); } [Test] public void ObjCClass () { using (var obj = new FrameworkTest ()) { - Assert.AreEqual (42, obj.Func (), "a"); + Assert.That (obj.Func (), Is.EqualTo (42), "a"); } } } diff --git a/tests/xharness/Jenkins/TestTasks/AppleTestTask.cs b/tests/xharness/Jenkins/TestTasks/AppleTestTask.cs index 896e9a506d18..851fb2a9d42e 100644 --- a/tests/xharness/Jenkins/TestTasks/AppleTestTask.cs +++ b/tests/xharness/Jenkins/TestTasks/AppleTestTask.cs @@ -35,7 +35,7 @@ public override void SetEnvironmentVariables (Process process) var xcodeRoot = Jenkins.Harness.XcodeRoot; process.StartInfo.EnvironmentVariables ["RootTestsDirectory"] = HarnessConfiguration.RootDirectory; - process.StartInfo.EnvironmentVariables ["MD_APPLE_SDK_ROOT"] = xcodeRoot; + process.StartInfo.EnvironmentVariables ["DEVELOPER_DIR"] = xcodeRoot; foreach (var kvp in Environment) { if (kvp.Value is null) { diff --git a/tests/xharness/Jenkins/TestVariationsFactory.cs b/tests/xharness/Jenkins/TestVariationsFactory.cs index 018b94238bda..90fed955f11d 100644 --- a/tests/xharness/Jenkins/TestVariationsFactory.cs +++ b/tests/xharness/Jenkins/TestVariationsFactory.cs @@ -131,10 +131,12 @@ IEnumerable GetTestData (RunTestTask test) yield return new TestData { Variation = "Debug (interpreter)", TestVariation = "interpreter", Ignored = ignore }; yield return new TestData { Variation = "Release (interpreter)", TestVariation = "release|interpreter", Ignored = ignore }; } + yield return new TestData { Variation = $"Release (compat inline Class.GetHandle)", TestVariation = "inline-class-gethandle-compat|release", Ignored = ignore }; + yield return new TestData { Variation = $"Release (strict inline Class.GetHandle)", TestVariation = "inline-class-gethandle-strict|release", Ignored = ignore }; yield return new TestData { Variation = $"Release (compat inline dlfcn)", TestVariation = "inline-dlfcn-methods-compat|release", Ignored = ignore }; yield return new TestData { Variation = $"Release (strict inline dlfcn, link sdk)", TestVariation = "inline-dlfcn-methods-strict|linksdk|release", Ignored = ignore }; if (mac_supports_arm64) - yield return new TestData { Variation = $"Release (NativeAOT, .NET 11 defaults)", TestVariation = "inline-dlfcn-methods-strict|nativeaot|release", Ignored = ignore, RuntimeIdentifier = arm64_sim_runtime_identifier }; // it's necessary to specify RID, because NativeAOT defaults to building for device + yield return new TestData { Variation = $"Release (NativeAOT, .NET 11 defaults)", TestVariation = "nativeaot-net11-defaults|release", Ignored = ignore, RuntimeIdentifier = arm64_sim_runtime_identifier }; // it's necessary to specify RID, because NativeAOT defaults to building for device break; case "introspection": if (mac_supports_arm64) @@ -170,6 +172,8 @@ IEnumerable GetTestData (RunTestTask test) yield return new TestData { Variation = "Release (NativeAOT)", TestVariation = "release|nativeaot", Ignored = ignore }; yield return new TestData { Variation = "Release (NativeAOT, ARM64)", TestVariation = "release|nativeaot", Ignored = !mac_supports_arm64 ? true : ignore, RuntimeIdentifier = arm64_runtime_identifier }; yield return new TestData { Variation = "Release (NativeAOT, x64)", TestVariation = "release|nativeaot", Ignored = ignore, RuntimeIdentifier = x64_runtime_identifier }; + if (mac_supports_arm64) + yield return new TestData { Variation = $"Release (NativeAOT, .NET 11 defaults)", TestVariation = "release|nativeaot-net11-defaults", Ignored = ignore }; yield return new TestData { Variation = "Release (trimmable static registrar, NativeAOT)", TestVariation = "trimmable-static-registrar|nativeaot|release", Ignored = ignore }; yield return new TestData { Variation = "Release (trimmable static registrar, NativeAOT, ARM64)", TestVariation = "trimmable-static-registrar|nativeaot|release", Ignored = !mac_supports_arm64 ? true : ignore, RuntimeIdentifier = arm64_runtime_identifier }; yield return new TestData { Variation = "Release (trimmable static registrar, NativeAOT, x64)", TestVariation = "trimmable-static-registrar|nativeaot|release", Ignored = ignore, RuntimeIdentifier = x64_runtime_identifier }; @@ -182,6 +186,8 @@ IEnumerable GetTestData (RunTestTask test) yield return new TestData { Variation = "Debug (interpreter)", TestVariation = "interpreter", Ignored = ignore }; yield return new TestData { Variation = "Release (interpreter)", TestVariation = "release|interpreter", Ignored = ignore }; } + yield return new TestData { Variation = $"Release (compat inline dlfcn)", TestVariation = "inline-dlfcn-methods-compat|release", Ignored = ignore }; + yield return new TestData { Variation = $"Release (strict inline dlfcn, link sdk)", TestVariation = "inline-dlfcn-methods-strict|linksdk|release", Ignored = ignore }; break; } break; diff --git a/tests/xtro-sharpie/UnitTests/UnitTests.csproj b/tests/xtro-sharpie/UnitTests/UnitTests.csproj index dd9a60e4b579..5bd7b152f1f2 100644 --- a/tests/xtro-sharpie/UnitTests/UnitTests.csproj +++ b/tests/xtro-sharpie/UnitTests/UnitTests.csproj @@ -6,9 +6,9 @@ - - - + + + diff --git a/tests/xtro-sharpie/UnitTests/Xtro.cs b/tests/xtro-sharpie/UnitTests/Xtro.cs index 9b4dd819c721..6037f79e44c1 100644 --- a/tests/xtro-sharpie/UnitTests/Xtro.cs +++ b/tests/xtro-sharpie/UnitTests/Xtro.cs @@ -29,7 +29,7 @@ public void RunTest () TestContext.AddTestAttachment (zippedReport, "HTML report (zipped)"); } - Assert.AreEqual (0, rv, "ExitCode"); + Assert.That (rv, Is.EqualTo (0), "ExitCode"); } } } diff --git a/tools/common/Application.cs b/tools/common/Application.cs index f2b8f7fc1882..756b0c623574 100644 --- a/tools/common/Application.cs +++ b/tools/common/Application.cs @@ -268,6 +268,14 @@ public bool PackageManagedDebugSymbols { public Version GetMacCatalystiOSVersion (Version macOSVersion) { +#if LEGACY_TOOLS + if (macOSVersion.Major >= 26 && Driver.SdkRoot is null) { + // this shouldn't happen for normal builds, nor for customers, so just show an internal 99 warning. + ErrorHelper.Warning (99, Errors.MX0099, $"No Xcode configured, assuming the macOS version {macOSVersion} is identical to the Mac Catalyst/iOS version."); + return macOSVersion; + } +#endif + if (!MacCatalystSupport.TryGetiOSVersion (Driver.GetFrameworkDirectory (this), macOSVersion, out var value, out var knownMacOSVersions)) throw ErrorHelper.CreateError (184, Errors.MX0184 /* Could not map the macOS version {0} to a corresponding Mac Catalyst version. Valid macOS versions are: {1} */, macOSVersion.ToString (), string.Join (", ", knownMacOSVersions.OrderBy (v => v))); diff --git a/tools/common/DerivedLinkContext.cs b/tools/common/DerivedLinkContext.cs index 743b1b768461..0f639be2e7b5 100644 --- a/tools/common/DerivedLinkContext.cs +++ b/tools/common/DerivedLinkContext.cs @@ -41,6 +41,9 @@ public class DerivedLinkContext : LinkContext { // true/false = corresponding constant value Dictionary? isdirectbinding_value; + // A map from Objective-C class name to C# type + Dictionary? objectiveCTypeInfo; + // Store interfaces the linker has linked away so that the static registrar can access them. public Dictionary> ProtocolImplementations { get; private set; } = new Dictionary> (); // Store types the linker has linked away so that the static registrar can access them. @@ -73,6 +76,7 @@ public AssemblyDefinition Corlib { return corlib; } } + public HashSet? CachedIsNSObject { get { return cached_isnsobject; } set { cached_isnsobject = value; } @@ -83,6 +87,11 @@ public HashSet? CachedIsNSObject { set { isdirectbinding_value = value; } } + public Dictionary? ObjectiveCTypeInfo { + get { return objectiveCTypeInfo; } + set { objectiveCTypeInfo = value; } + } + public IList DataContract { get { return srs_data_contract; @@ -237,8 +246,11 @@ public void AddLinkedAwayType (TypeDefinition td) } #if !LEGACY_TOOLS - public bool HasAvailabilityAttributesShowingUnavailableInSimulator (ICustomAttributeProvider provider, MethodDefinition? methodForErrorReporting = null) + public bool HasAvailabilityAttributesShowingUnavailableInSimulator (ICustomAttributeProvider? provider, MethodDefinition? methodForErrorReporting = null) { + if (provider is null) + return false; + if (!App.IsSimulatorBuild) { LinkerConfiguration.Report (LinkerConfiguration.Context, ErrorHelper.CreateError (99, "HasAvailabilityAttributesShowingUnavailableInSimulator should not be called when not building for the simulator. Please file an issue at https://github.com/dotnet/macios/issues.")); return false; diff --git a/tools/common/Driver.cs b/tools/common/Driver.cs index 50bd8dbd3cce..5ff3ad4d8fe9 100644 --- a/tools/common/Driver.cs +++ b/tools/common/Driver.cs @@ -69,6 +69,11 @@ static void ParseOptions (Application app, Mono.Options.OptionSet options, strin options.Add ("rid=", "The runtime identifier we're building for", v => { app.RuntimeIdentifier = v; }); + options.Add ("xcode-version=", "The Xcode version we're building with", v => { + if (!Version.TryParse (v, out var xcodeVersion)) + throw ErrorHelper.CreateError (26, Errors.MX0026, $"xcode-version:{v}", "Expected a valid version string."); + Driver.XcodeVersion = xcodeVersion; + }); try { app.RootAssemblies.AddRange (options.Parse (args)); @@ -230,7 +235,12 @@ public static string? XcodeProductVersion { static Version? xcode_version; public static Version XcodeVersion { get { - return xcode_version!; + if (xcode_version is null) + throw ErrorHelper.CreateError (99, Errors.MX0099, "The Xcode version has not been configured. Pass --xcode-version or configure an Xcode installation."); + return xcode_version; + } + set { + xcode_version = value; } } diff --git a/tools/common/FileCopier.cs b/tools/common/FileCopier.cs index 98a8e1a27f5d..06d1176453bc 100644 --- a/tools/common/FileCopier.cs +++ b/tools/common/FileCopier.cs @@ -394,7 +394,7 @@ static bool IsUptodate (IEnumerable sources, IEnumerable targets return true; } - [DllImport ("/usr/lib/libSystem.dylib", SetLastError = true, EntryPoint = "strerror")] + [DllImport ("libc", SetLastError = true, EntryPoint = "strerror")] static extern IntPtr _strerror (int errno); internal static string strerror (int errno) diff --git a/tools/common/FileUtils.cs b/tools/common/FileUtils.cs index f8b3c617674f..7b406fd24ed6 100644 --- a/tools/common/FileUtils.cs +++ b/tools/common/FileUtils.cs @@ -75,5 +75,19 @@ public static bool UpdateFile (string targetFile, Action createOutput) } } + + public static void WriteIfDifferent (string path, string contents, Action log) + { + if (!File.Exists (path)) { + log ($"File '{path}' contents are not up-to-date, because the file doesn't exist."); + File.WriteAllText (path, contents); + } else if (string.Equals (contents, File.ReadAllText (path), StringComparison.Ordinal)) { + log ($"File '{path}' contents are up-to-date."); + return; + } else { + log ($"File '{path}' contents are not up-to-date."); + File.WriteAllText (path, contents); + } + } } } diff --git a/tools/common/PathUtils.cs b/tools/common/PathUtils.cs index 19dcc31df8fe..355253f5c2a7 100644 --- a/tools/common/PathUtils.cs +++ b/tools/common/PathUtils.cs @@ -38,7 +38,7 @@ static char ToOrdinalIgnoreCase (char c) return path; } - [DllImport ("/usr/lib/libc.dylib")] + [DllImport ("libc")] static extern IntPtr realpath (string path, IntPtr buffer); #if NET @@ -422,5 +422,25 @@ static bool IsLongPathsEnabledRegistry { } } } + + public static void CreateDirectoryForFile (string? file) + { +#if NET + if (string.IsNullOrEmpty (file)) +#else + if (string.IsNullOrEmpty (file) || file is null) +#endif + return; + + var dir = Path.GetDirectoryName (file); +#if NET + if (string.IsNullOrEmpty (dir)) +#else + if (string.IsNullOrEmpty (dir) || dir is null) +#endif + return; + + Directory.CreateDirectory (dir); + } } } diff --git a/tools/common/StaticRegistrar.cs b/tools/common/StaticRegistrar.cs index 2170362d0c79..9891a0c2ec6e 100644 --- a/tools/common/StaticRegistrar.cs +++ b/tools/common/StaticRegistrar.cs @@ -1591,7 +1591,7 @@ protected override IEnumerable GetProtocolMemberAttribu } #if !LEGACY_TOOLS - bool GetDotNetAvailabilityAttribute (ICustomAttribute ca, ApplePlatform currentPlatform, out Version? sdkVersion, out string? message) + public bool GetDotNetAvailabilityAttribute (ICustomAttribute ca, ApplePlatform currentPlatform, out Version? sdkVersion, out string? message) { var caType = ca.AttributeType; @@ -1601,6 +1601,7 @@ bool GetDotNetAvailabilityAttribute (ICustomAttribute ca, ApplePlatform currentP string supportedPlatformAndVersion; switch (ca.ConstructorArguments.Count) { case 1: + case 2: // second argument can be a message supportedPlatformAndVersion = (string) ca.ConstructorArguments [0].Value; break; default: @@ -1679,7 +1680,7 @@ bool CollectAvailabilityAttributes (IEnumerable attributes, ou return false; } - protected override Version? GetSdkIntroducedVersion (TypeReference obj, out string? message) + public override Version? GetSdkIntroducedVersion (TypeReference obj, out string? message) { TypeDefinition td = obj.Resolve (); @@ -2025,7 +2026,7 @@ public bool IsCustomType (ObjCType type) return false; } - bool IsPlatformType (TypeReference type) + public bool IsPlatformType (TypeReference type) { if (type.IsNested) return false; diff --git a/tools/common/Target.cs b/tools/common/Target.cs index 4fea94015be1..07b628d858a4 100644 --- a/tools/common/Target.cs +++ b/tools/common/Target.cs @@ -64,7 +64,7 @@ public void ExtractNativeLinkInfo (List exceptions) } #endif // !LEGACY_TOOLS - [DllImport (Constants.libSystemLibrary, SetLastError = true)] + [DllImport ("libc", SetLastError = true)] static extern string realpath (string path, IntPtr zero); public static string GetRealPath (string path, bool warnIfNoSuchPathExists = true) diff --git a/tools/devops/automation/scripts/bash/fix-github-ssh-key.sh b/tools/devops/automation/scripts/bash/fix-github-ssh-key.sh deleted file mode 100755 index a603c99bc60d..000000000000 --- a/tools/devops/automation/scripts/bash/fix-github-ssh-key.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -ex - -# ensure that we do remove the old ssh key from github which was leaked: https://blog.gitguardian.com/github-exposed-private-ssh-key/ - -ssh-keygen -R github.com -{ - echo "github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl" - echo "github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=" - echo "github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=" -} >> ~/.ssh/known_hosts diff --git a/tools/devops/automation/templates/common/setup.yml b/tools/devops/automation/templates/common/setup.yml index a713adac8593..a80833941c2f 100644 --- a/tools/devops/automation/templates/common/setup.yml +++ b/tools/devops/automation/templates/common/setup.yml @@ -22,9 +22,6 @@ steps: name: disableCodeQLOnArm64 condition: and(succeeded(), eq('${{ parameters.disableCodeQL }}', 'true')) -- bash: $(Build.SourcesDirectory)/$(BUILD_REPOSITORY_TITLE)/tools/devops/automation/scripts/bash/fix-github-ssh-key.sh - displayName: 'Fix GitHub SSH host key' - - pwsh: '& "$Env:SYSTEM_DEFAULTWORKINGDIRECTORY/$Env:BUILD_REPOSITORY_TITLE/tools/devops/automation/scripts/show_bot_info.ps1"' displayName: 'Show Bot Info' diff --git a/tools/devops/automation/templates/tests/run-tests.yml b/tools/devops/automation/templates/tests/run-tests.yml index 188474aa28ea..40c85db23a1a 100644 --- a/tools/devops/automation/templates/tests/run-tests.yml +++ b/tools/devops/automation/templates/tests/run-tests.yml @@ -172,6 +172,15 @@ steps: continueOnError: true condition: succeededOrFailed() +# Upload updated expected app size files if the app size tests produced any. +- task: PublishPipelineArtifact@1 + displayName: 'Publish Artifact: Updated expected app size files' + inputs: + targetPath: '$(Build.ArtifactStagingDirectory)/updated-expected-sizes' + artifactName: '${{ parameters.uploadPrefix }}updated-expected-sizes-${{ parameters.testPrefix }}-$(System.JobAttempt)' + continueOnError: true + condition: succeededOrFailed() + - pwsh: | $summaryName = "TestSummary-${{ parameters.testPrefix }}.md" $summaryPath = "$Env:SYSTEM_DEFAULTWORKINGDIRECTORY/$(BUILD_REPOSITORY_TITLE)/tests/TestSummary.md" diff --git a/tools/dotnet-linker/AppBundleRewriter.cs b/tools/dotnet-linker/AppBundleRewriter.cs index 5013997108d1..1b3908f009ea 100644 --- a/tools/dotnet-linker/AppBundleRewriter.cs +++ b/tools/dotnet-linker/AppBundleRewriter.cs @@ -70,6 +70,7 @@ public AssemblyDefinition SystemConsoleAssembly { Dictionary> type_map = new (); Dictionary method_map = new (); Dictionary field_map = new (); + Dictionary created_types = new (); public AppBundleRewriter (LinkerConfiguration configuration) { @@ -1450,6 +1451,7 @@ public void ClearCurrentAssembly () type_map.Clear (); method_map.Clear (); field_map.Clear (); + created_types.Clear (); } public CustomAttribute CreateAttribute (MethodReference constructor) @@ -1676,5 +1678,53 @@ static bool DebugAttributes { return debug_attributes.Value; } } + + public TypeDefinition GetOrCreateType (ModuleDefinition module, string @namespace, string @typename, out bool created) + { + created = false; + + var fullName = @namespace + "." + typename; + if (!created_types.TryGetValue (fullName, out var cachedTypeDefinition)) { + cachedTypeDefinition = module.Types.FirstOrDefault (t => t.Namespace == @namespace && t.Name == typename); + if (cachedTypeDefinition is null) { + cachedTypeDefinition = new TypeDefinition (@namespace, typename, TypeAttributes.Public | TypeAttributes.Sealed, module.TypeSystem.Object); + module.Types.Add (cachedTypeDefinition); + created = true; + } + created_types [fullName] = cachedTypeDefinition; + } + + return cachedTypeDefinition; + } + + public MethodDefinition CreateInternalPInvoke (ModuleDefinition module, string @namespace, string @typename, string methodName, out bool created) + { + var cachedTypeDefinition = GetOrCreateType (module, @namespace, @typename, out _); + var nativeMethod = methodName; + var rv = cachedTypeDefinition.Methods.FirstOrDefault (m => m.Name == methodName); + if (rv is not null) { + created = false; + return rv; // already exists, no need to create it again + } + + // [DllImport ("__Internal")] + // static extern IntPtr {methodName} (); + + rv = new MethodDefinition (methodName, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.PInvokeImpl, System_IntPtr); + rv.IsPreserveSig = true; + + var mod = module.ModuleReferences.FirstOrDefault (mr => mr.Name == "__Internal"); + if (mod is null) { + mod = new ModuleReference ("__Internal"); + module.ModuleReferences.Add (mod); + } + rv.PInvokeInfo = new PInvokeInfo (PInvokeAttributes.CharSetNotSpec | PInvokeAttributes.CallConvCdecl, nativeMethod, mod); + + cachedTypeDefinition.Methods.Add (rv); + + created = true; + + return rv; + } } } diff --git a/tools/dotnet-linker/LinkerConfiguration.cs b/tools/dotnet-linker/LinkerConfiguration.cs index 8b3da28d0bf7..397ff2b228c9 100644 --- a/tools/dotnet-linker/LinkerConfiguration.cs +++ b/tools/dotnet-linker/LinkerConfiguration.cs @@ -32,6 +32,7 @@ public class LinkerConfiguration { public bool HybridGlobalization { get; private set; } public InlineDlfcnMethodsMode InlineDlfcnMethods { get; set; } public bool InlineDlfcnMethodsEnabled => InlineDlfcnMethods != InlineDlfcnMethodsMode.Disabled; + public InlineClassGetHandleMode InlineClassGetHandle { get; set; } // Per-assembly field symbols collected by InlineDlfcnMethodsStep, keyed by assembly name. public Dictionary> InlinedDlfcnFields { get; } = new Dictionary> (); // All [Field] symbol names collected by ProcessExportedFields, used in compatibility mode. @@ -45,6 +46,7 @@ public class LinkerConfiguration { public string RelativeAppBundlePath { get; private set; } = string.Empty; public Version? SdkVersion { get; private set; } public string SdkRootDirectory { get; private set; } = string.Empty; + public string TypeMapFilePath { get; set; } = string.Empty; public int Verbosity => Driver.Verbosity; public string XamarinNativeLibraryDirectory { get; private set; } = string.Empty; @@ -213,11 +215,17 @@ public static LinkerConfiguration GetInstance (LinkContext context) case "FrameworkAssembly": FrameworkAssemblies.Add (value); break; + case "InlineClassGetHandle": + if (Enum.TryParse (value, true, out var inlineClassGetHandleMode)) + InlineClassGetHandle = inlineClassGetHandleMode; + else if (string.IsNullOrEmpty (value)) + InlineClassGetHandle = InlineClassGetHandleMode.Disabled; + else + throw new InvalidOperationException ($"Unknown InlineClassGetHandle value: {value}"); + break; case "InlineDlfcnMethods": if (Enum.TryParse (value, true, out var inlineDlfcnMode)) InlineDlfcnMethods = inlineDlfcnMode; - else if (string.Equals (value, "compatibility", StringComparison.OrdinalIgnoreCase)) - InlineDlfcnMethods = InlineDlfcnMethodsMode.Compat; else if (string.IsNullOrEmpty (value)) InlineDlfcnMethods = InlineDlfcnMethodsMode.Disabled; else @@ -390,6 +398,9 @@ public static LinkerConfiguration GetInstance (LinkContext context) case "TypeMapAssemblyName": Application.TypeMapAssemblyName = value; break; + case "TypeMapFilePath": + TypeMapFilePath = value; + break; case "TypeMapOutputDirectory": Application.TypeMapOutputDirectory = value; break; @@ -583,6 +594,7 @@ public void Write () Console.WriteLine ($" SdkRootDirectory: {SdkRootDirectory}"); Console.WriteLine ($" SdkVersion: {SdkVersion}"); Console.WriteLine ($" TypeMapAssemblyName: {Application.TypeMapAssemblyName}"); + Console.WriteLine ($" TypeMapFilePath: {TypeMapFilePath}"); Console.WriteLine ($" TypeMapOutputDirectory: {Application.TypeMapOutputDirectory}"); Console.WriteLine ($" UseInterpreter: {Application.UseInterpreter}"); Console.WriteLine ($" UseLlvm: {Application.IsLLVM}"); @@ -681,4 +693,12 @@ public enum InlineDlfcnMethodsMode { Disabled, Strict, Compat, + Compatibility = Compat, +} + +public enum InlineClassGetHandleMode { + Disabled, + Strict, + Compat, + Compatibility = Compat, } diff --git a/tools/dotnet-linker/Steps/InlineClassGetHandleStep.cs b/tools/dotnet-linker/Steps/InlineClassGetHandleStep.cs new file mode 100644 index 000000000000..1a48cba7b3b0 --- /dev/null +++ b/tools/dotnet-linker/Steps/InlineClassGetHandleStep.cs @@ -0,0 +1,264 @@ +using System.Linq; +using System.Text; + +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Linker; +using Mono.Tuner; + +using Xamarin.Bundler; +using Xamarin.Utils; + +#nullable enable + +namespace Xamarin.Linker.Steps; + +// See docs/code/class-handles.md for an overview of class handle handling. + +// Find all the references to Objective-C classes for each assembly. +// * If an assembly is trimmed, we replace calls to (inline) Class.GetHandle with a P/Invoke that fetches the class in question. +// * If an assembly is not trimmed, we do not inline Class.GetHandle, but we keep a list of all the Objective-C classes that are used, so that we can tell the native linker about them so they're not linked away by the native linker. +// +// The sticky problem is that we can't inspect the managed output from NativeAOT, which means +// we can't list the Objective-C classes NativeAOT-compiled assemblies using. To get around this +// problem, we convert calls to Class.GetHandle to a P/Invoke which fetches the native Objective-C +// class handle directly - because we _can_ list the P/Invoke calls from NativeAOT-compiled code. +// +// For non-trimmed assemblies, we don't need to do this, because we know nothing from the assembly +// will be trimmed away. This has the added advantage of being Hot Reload compatible, because we +// can't modify assemblies when we're doing Hot Reload. + +public class InlineClassGetHandleStep : AssemblyModifierStep { + + protected override string Name { get; } = "Inline Class GetHandle"; + protected override int ErrorCode { get; } = 2262; + + bool strictMode; + bool? inlining_enabled; + + Dictionary objectiveCTypeMap = new (); + + public const string PInvokePrefix = "xamarin_Class_GetHandle_"; + public const string PInvokeSuffix = "_Native"; + + protected override void TryProcess () + { + strictMode = Configuration.InlineClassGetHandle == InlineClassGetHandleMode.Strict; + + if (strictMode && Configuration.Application.Registrar == Bundler.RegistrarMode.Dynamic) { + Report (ErrorHelper.CreateError (Configuration.Application, 2262, null, Errors.MX2262)); + } + + objectiveCTypeMap = DerivedLinkContext.StaticRegistrar.Types.ToDictionary (v => v.Value.ExportedName, v => v.Value); + + if (!string.IsNullOrEmpty (Configuration.TypeMapFilePath)) { + var sb = new StringBuilder (); + foreach (var info in objectiveCTypeMap.Values.OrderBy (v => v.ExportedName)) { + var td = info.Type.Resolve (); + if (td is null) + continue; + var introduced = DerivedLinkContext.StaticRegistrar.GetSdkIntroducedVersion (td, out _); + Frameworks.TryGetFramework (App, td, out string? framework); + sb.AppendLine ($"Class={info.ExportedName}|Framework={framework}|Introduced={introduced}|IsWrapper={info.IsWrapper}|IsStubClass={info.IsStubClass}"); + } + Driver.WriteIfDifferent (Configuration.TypeMapFilePath, sb.ToString ()); + } + + base.TryProcess (); + } + + protected override bool IsActiveFor (AssemblyDefinition assembly) + { + if (!Configuration.Profile.IsOrReferencesProductAssembly (assembly)) + return false; + + // we have to process both trimmed and non-trimmed assemblies. + + return true; + } + + protected override bool ModifyAssembly (AssemblyDefinition assembly) + { + inlining_enabled = Annotations.GetAction (assembly) == AssemblyAction.Link; + var modified = base.ModifyAssembly (assembly); + inlining_enabled = null; + return modified; + } + + protected override bool ProcessType (TypeDefinition type) + { + var modified = false; + + if (inlining_enabled == true) { + modified |= ProcessMethods (type); + } else { + if (ListExportedSymbols.TryGetRequiredObjectiveCType (DerivedLinkContext, type, out var exportedName)) { + DerivedLinkContext.RequiredSymbols.AddObjectiveCClass (exportedName).AddMember (type); + } + } + return modified; + } + + MethodDefinition GetOrCreatePInvokeMethod (MethodDefinition callingMethod, string objectiveCClassName) + { + // [DllImport ("__Internal")] + // static extern IntPtr xamarin_Class_GetClassHandle_{objectiveCClassName}_Native (); + + return abr.CreateInternalPInvoke (callingMethod.Module, "ObjCRuntime", "Class", $"{PInvokePrefix}{objectiveCClassName}{PInvokeSuffix}", out _); + } + + protected override bool ProcessMethod (MethodDefinition method) + { + var modified = false; + + if (!method.HasBody) + return modified; + + if (method.DeclaringType.Name == "Class" && method.DeclaringType.Namespace == "ObjCRuntime") + return modified; // don't process the Class methods themselves + + bool isOurOwnCode () + { + // Don't show warnings for a few places in our own code where we call Class.GetHandle in un-inlinable ways. + switch (method.DeclaringType.Namespace) { + case "Registrar": + switch (method.DeclaringType.Name) { + case "DynamicRegistrar": + switch (method.Name) { + case "OnReloadType": + case "OnRegisterType": + return true; + } + break; + } + break; + } + return false; + } + + foreach (var instr in method.Body.Instructions) { + if (instr.Operand is not MethodReference mr) + continue; + if (mr.DeclaringType.Name != "Class" || mr.DeclaringType.Namespace != "ObjCRuntime") + continue; + if (mr.Name != "GetHandle" && mr.Name != "GetHandleIntrinsic") + continue; + if (mr.Parameters.Count != 1) + continue; + if (!mr.Parameters [0].ParameterType.Is ("System", "String")) + continue; + if (!mr.ReturnType.Is ("ObjCRuntime", "NativeHandle")) + continue; + + var ldstr = instr.Previous; + if (ldstr.OpCode != OpCodes.Ldstr) { + if (!isOurOwnCode ()) + Driver.Log (3, "Unknown or unsupported pattern in call to Class.GetHandle in '{0}': {1}. The call will not be inlined.", FormatMethod (method), ldstr); + continue; + } + if (ldstr.Operand is not string objectiveCClassName) { + if (!isOurOwnCode ()) + Driver.Log (3, "Unknown or unsupported pattern in call to Class.GetHandle in '{0}': {1}. The call will not be inlined.", FormatMethod (method), ldstr.Operand); + continue; + } + + if (!objectiveCTypeMap.TryGetValue (objectiveCClassName, out var objCType)) { + Driver.Log (3, "Could not find a managed type for the Objective-C type '{1}' in the call to Class.GetHandle in '{0}', assuming the Objective-C type is available in the simulator.", FormatMethod (method), objectiveCClassName); + } + + if (!strictMode) { + if (objCType is not null && objCType.Type == method.DeclaringType) { + // This is a call to Class.GetHandle for the same class that it's being called from, this is OK. + } else if (ListExportedSymbols.TryGetRequiredObjectiveCType (DerivedLinkContext, method.DeclaringType, out var exportedName)) { + if (exportedName != objectiveCClassName) { + Driver.Log (3, "The call to Class.GetHandle in '{0}' is trying to get the handle for the Objective-C class '{1}', but the declaring type's exported name is '{2}', not '{1}'. Since we're in compat mode, we're assuming the class should not be preserved.", FormatMethod (method), objectiveCClassName, exportedName); + continue; + } + } else { + if (App.StaticRegistrar.GetCategoryAttribute (method.DeclaringType) is not null) + Driver.Log (3, "The call to Class.GetHandle in '{0}' is trying to get the handle for the Objective-C class '{1}', but we couldn't determine whether this class should be statically preserved or not. Since we're in compat mode, we're assuming the class should not be statically preserved.", FormatMethod (method), objectiveCClassName); + continue; + } + } + + // Check if the Objective-C class is listed as a ReferenceNativeSymbol with Ignore mode, and if so, don't inline the call to Class.GetHandle (because the native symbol won't be available at link time) + var existingSymbol = DerivedLinkContext.RequiredSymbols.Find (Symbol.ObjectiveCPrefix + objectiveCClassName); + if (existingSymbol is not null && existingSymbol.Type == SymbolType.ObjectiveCClass && existingSymbol.Mode == SymbolMode.Ignore) { + Driver.Log (3, "Not inlining the call to Class.GetHandle (\"{0}\") in method {1} because the class is listed as a ReferenceNativeSymbol with Ignore mode.", objectiveCClassName, FormatMethod (method)); + continue; + } + + if (objCType is not null) { + if (DerivedLinkContext.App.IsSimulatorBuild) { + if (DerivedLinkContext.HasAvailabilityAttributesShowingUnavailableInSimulator (objCType.Type.Resolve (), method)) { + Driver.Log (3, "Not inlining the call to Class.GetHandle (\"{0}\") in method {1} because the type is marked with an attribute indicating it's not available in the simulator.", objectiveCClassName, FormatMethod (method)); + continue; + } + } + + if (IsUnsupported (objCType.Type.Resolve ())) { + Driver.Log (3, "Not inlining the call to Class.GetHandle (\"{0}\") in method {1} because the type is marked with an [UnsupportedOSPlatform] attribute.", objectiveCClassName, FormatMethod (method)); + continue; + } + + if (objCType.Methods is null && DerivedLinkContext.StaticRegistrar.IsPlatformType (objCType.Type) && !objCType.IsProtocol && !objCType.IsCategory && objCType.IsModel) { + // The static registrar skips generating code for this type, so we shouldn't inline calls to Class.GetHandle for it, because the P/Invoke we generate won't be able to find the native symbol for it. + continue; + } + + if (Frameworks.TryGetFramework (App, objCType.Type.Resolve (), out Framework? framework) && framework.IsFrameworkUnavailable (App)) { + Driver.Log (3, "Not inlining the call to Class.GetHandle (\"{0}\") in method {1} because the framework {2} is unavailable.", objectiveCClassName, FormatMethod (method), framework.Name); + continue; + } + + if (objCType.Type.Is ("UIKit", "UITitlebar")) { + // UITitlebar is a weird special case, the class exists in the headers, and it's documented online, but it's not possible to link with it (not even in an Xcode project, it's not in any .tbd files). + continue; + } + } + + ldstr.OpCode = OpCodes.Call; + ldstr.Operand = GetOrCreatePInvokeMethod (method, objectiveCClassName); + + instr.OpCode = OpCodes.Call; + instr.Operand = abr.NativeObject_op_Implicit_NativeHandle; + + modified = true; + } + + return modified; + } + + bool IsUnsupported (TypeDefinition? type) + { + if (type is null) + return false; + + if (!type.HasCustomAttributes) + return false; + + foreach (var ca in type.CustomAttributes) { + if (!ca.AttributeType.Is ("System.Runtime.Versioning", "UnsupportedOSPlatformAttribute")) + continue; + + if (!DerivedLinkContext.StaticRegistrar.GetDotNetAvailabilityAttribute (ca, App.Platform, out var sdkVersion, out _)) + continue; + + if (sdkVersion is null) + return true; // if there's no version, then it's always unavailable + + return sdkVersion <= App.SdkVersion; + } + + return false; + } + + static string FormatMethod (MethodReference method) + { + var rv = method.FullName; + var idx = rv.IndexOf (' '); + if (idx > 0) + rv = rv.Substring (idx + 1); + return rv; + } +} diff --git a/tools/dotnet-linker/Steps/InlineDlfcnMethodsStep.cs b/tools/dotnet-linker/Steps/InlineDlfcnMethodsStep.cs index d6b214986d02..99b67d4a9984 100644 --- a/tools/dotnet-linker/Steps/InlineDlfcnMethodsStep.cs +++ b/tools/dotnet-linker/Steps/InlineDlfcnMethodsStep.cs @@ -28,6 +28,9 @@ public class InlineDlfcnMethodsStep : AssemblyModifierStep { bool strictMode; + public const string PInvokePrefix = "xamarin_Dlfcn_"; + public const string PInvokeSuffix = "_Native"; + protected override void TryProcess () { strictMode = Configuration.InlineDlfcnMethods == InlineDlfcnMethodsMode.Strict; @@ -99,18 +102,15 @@ TypeDefinition GetDlfcnType (ModuleDefinition module, string @namespace, string? { var frameworkOverride = !string.IsNullOrEmpty (fieldLibraryName) ? fieldLibraryName : current_framework; var ns = string.IsNullOrEmpty (frameworkOverride) ? @namespace : frameworkOverride; - var dlfcn = module.Types.FirstOrDefault (t => t.Namespace == ns && t.Name == "Dlfcn"); - if (dlfcn is null) { - dlfcn = new TypeDefinition (ns, "Dlfcn", TypeAttributes.NotPublic | TypeAttributes.Sealed, module.TypeSystem.Object); - module.Types.Add (dlfcn); - + var rv = abr.GetOrCreateType (module, ns, "Dlfcn", out var created); + if (created) { if (!string.IsNullOrEmpty (frameworkOverride)) { - var attrib = new CustomAttribute (abr.ObjectiveCFrameworkAttribute_ctor_String); + var attrib = abr.CreateAttribute (abr.ObjectiveCFrameworkAttribute_ctor_String); attrib.ConstructorArguments.Add (new CustomAttributeArgument (abr.System_String, frameworkOverride)); - dlfcn.CustomAttributes.Add (attrib); + rv.CustomAttributes.Add (attrib); } } - return dlfcn; + return rv; } void AddField (string assemblyName, string symbolName) @@ -124,30 +124,13 @@ void AddField (string assemblyName, string symbolName) MethodDefinition GetOrCreatePInvokeMethod (MethodDefinition callingMethod, string symbolName) { - var dlfcn = GetDlfcnType (callingMethod); - var methodName = $"xamarin_Dlfcn_{symbolName}_Native"; - var nativeMethod = methodName; - var rv = dlfcn.Methods.FirstOrDefault (m => m.Name == methodName); - if (rv is not null) - return rv; // already exists, no need to create it again - // [DllImport ("__Internal")] // static extern IntPtr xamarin_Dlfcn_{symbolName}_Native (); - rv = new MethodDefinition (methodName, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.PInvokeImpl, abr.System_IntPtr); - rv.IsPreserveSig = true; - - var mod = callingMethod.Module.ModuleReferences.FirstOrDefault (mr => mr.Name == "__Internal"); - if (mod is null) { - mod = new ModuleReference ("__Internal"); - callingMethod.Module.ModuleReferences.Add (mod); - } - rv.PInvokeInfo = new PInvokeInfo (PInvokeAttributes.CharSetNotSpec | PInvokeAttributes.CallConvCdecl, nativeMethod, mod); - - dlfcn.Methods.Add (rv); - - AddField (callingMethod.Module.Assembly.Name.Name, symbolName); - + var methodName = $"{PInvokePrefix}{symbolName}{PInvokeSuffix}"; + var rv = abr.CreateInternalPInvoke (callingMethod.Module, callingMethod.DeclaringType.Namespace, "Dlfcn", methodName, out var created); + if (created) + AddField (callingMethod.Module.Assembly.Name.Name, symbolName); return rv; } diff --git a/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs b/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs index eda79a994f73..b74d18cddca7 100644 --- a/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs +++ b/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs @@ -18,7 +18,6 @@ namespace Xamarin.Linker.Steps { public class ListExportedSymbols : BaseStep { PInvokeWrapperGenerator? state; - bool is_product_assembly; PInvokeWrapperGenerator? State { get { @@ -80,8 +79,6 @@ protected override void ProcessAssembly (AssemblyDefinition assembly) if (!hasSymbols) return; - is_product_assembly = Configuration.Profile.IsProductAssembly (assembly); - var modified = false; foreach (var type in assembly.MainModule.Types) modified |= ProcessType (type); @@ -114,40 +111,41 @@ bool ProcessType (TypeDefinition type) void AddRequiredObjectiveCType (TypeDefinition type) { + if (TryGetRequiredObjectiveCType (DerivedLinkContext, type, out var exportedName)) + DerivedLinkContext.RequiredSymbols.AddObjectiveCClass (exportedName).AddMember (type); + } + + // Returns true if the specified type represents an Objective-C class that should be referenced as a required symbol, so that the native linker doesn't link it away. + public static bool TryGetRequiredObjectiveCType (DerivedLinkContext derivedLinkContext, TypeDefinition type, [NotNullWhen (true)] out string? exportedName) + { + exportedName = null; + // The product assembly only has one type we may need to keep: XamarinSwiftFunctions - if (is_product_assembly) { + if (derivedLinkContext.LinkerConfiguration.Profile.IsProductAssembly (type.Module.Assembly)) { switch (type.Name) { case "XamarinSwiftFunctions": break; default: - return; + return false; } } - var staticRegistrar = DerivedLinkContext.StaticRegistrar; + var staticRegistrar = derivedLinkContext.StaticRegistrar; if (staticRegistrar is null) - return; + return false; - var registerAttribute = staticRegistrar.GetRegisterAttribute (type); - if (registerAttribute is null) - return; + if (!staticRegistrar.TryGetExportedTypeName (type, out exportedName)) + return false; - if (!registerAttribute.IsWrapper) - return; - - if (staticRegistrar.HasProtocolAttribute (type)) - return; - - if (DerivedLinkContext.App.RequireLinkWithAttributeForObjectiveCClassSearch) { + if (derivedLinkContext.App.RequireLinkWithAttributeForObjectiveCClassSearch) { var has_linkwith_attributes = false; - if (DerivedLinkContext.App.Assemblies.TryGetValue (type.Module.Assembly, out var asm)) + if (derivedLinkContext.App.Assemblies.TryGetValue (type.Module.Assembly, out var asm)) has_linkwith_attributes = asm.HasLinkWithAttributes; if (!has_linkwith_attributes) - return; + return false; } - var exportedName = staticRegistrar.GetExportedTypeName (type, registerAttribute); - DerivedLinkContext.RequiredSymbols.AddObjectiveCClass (exportedName).AddMember (type); + return true; } bool ProcessMethod (MethodDefinition method) @@ -191,13 +189,18 @@ bool ProcessMethod (MethodDefinition method) switch (pinfo.Module.Name) { case "__Internal": - // For NativeAOT builds, don't add inlined dlfcn P/Invoke wrappers as - // required symbols: only the surviving ones will have native code generated, - // so force-referencing all of them causes linker errors for symbols that - // NativeAOT trimmed away. For non-NativeAOT builds, the wrappers are resolved - // via dlsym and need the -u flags to be exported from the binary. - if (Configuration.InlineDlfcnMethodsEnabled && Configuration.Application.XamarinRuntime == XamarinRuntime.NativeAOT && pinfo.EntryPoint.StartsWith ("xamarin_Dlfcn_", StringComparison.Ordinal)) - break; + if (Configuration.Application.XamarinRuntime == XamarinRuntime.NativeAOT) { + // For NativeAOT builds, don't add inlined dlfcn P/Invoke wrappers as + // required symbols: only the surviving ones will have native code generated, + // so force-referencing all of them causes linker errors for symbols that + // NativeAOT trimmed away. For non-NativeAOT builds, the wrappers are resolved + // via dlsym and need the -u flags to be exported from the binary. + if (Configuration.InlineDlfcnMethodsEnabled && pinfo.EntryPoint.StartsWith (InlineDlfcnMethodsStep.PInvokePrefix, StringComparison.Ordinal)) + break; + // Same goes for inlined Class.GetHandle calls. + if (Configuration.InlineClassGetHandle != InlineClassGetHandleMode.Disabled && pinfo.EntryPoint.StartsWith (InlineClassGetHandleStep.PInvokePrefix, StringComparison.Ordinal)) + break; + } Driver.Log (4, "Adding native reference to {0} in {1} because it's referenced by {2} in {3}.", pinfo.EntryPoint, pinfo.Module.Name, method.FullName, method.Module.Name); DerivedLinkContext.RequiredSymbols.AddFunction (pinfo.EntryPoint).AddMember (method); break; diff --git a/tools/mtouch/Errors.designer.cs b/tools/mtouch/Errors.designer.cs index ee92d9580d81..7c3f1861b4ab 100644 --- a/tools/mtouch/Errors.designer.cs +++ b/tools/mtouch/Errors.designer.cs @@ -3596,6 +3596,15 @@ public static string MX2261 { } } + /// + /// Looks up a localized string similar to The 'InlineClassGetHandle' option is set to 'Strict', but we're using the dynamic registrar. This is not a supported configuration, because 'Strict' mode requires exported Objective-C classes to be available at compile time, but the dynamic registrar will create them at runtime. Please either change the 'InlineClassGetHandle' option to 'Disabled' or 'Compat', or switch to using the static registrar.. + /// + public static string MX2262 { + get { + return ResourceManager.GetString("MX2262", resourceCulture); + } + } + /// /// Looks up a localized string similar to Could not {0} the assembly '{1}'. /// diff --git a/tools/mtouch/Errors.resx b/tools/mtouch/Errors.resx index 987d7c75e479..cc89125d1ff1 100644 --- a/tools/mtouch/Errors.resx +++ b/tools/mtouch/Errors.resx @@ -1131,6 +1131,12 @@ '{0}' has multiple SupportedSimulator attributes for the '{1}' platform. Please file an issue at https://github.com/dotnet/macios/issues/new + + The 'InlineClassGetHandle' option is set to 'Strict', but we're using the dynamic registrar. This is not a supported configuration, because 'Strict' mode requires exported Objective-C classes to be available at compile time, but the dynamic registrar will create them at runtime. Please either change the 'InlineClassGetHandle' option to 'Disabled' or 'Compat', or switch to using the static registrar. + + + + diff --git a/tools/mtouch/Makefile b/tools/mtouch/Makefile index 0ad70dd239a7..d48cc4bd1eaf 100644 --- a/tools/mtouch/Makefile +++ b/tools/mtouch/Makefile @@ -35,18 +35,21 @@ $(abspath Constants.cs): Constants.cs.in Makefile $(TOP)/Make.config.inc # define RunRegistrar .libs/Microsoft.$(9).registrar.$(10)%m .libs/Microsoft.$(9).registrar.$(10)%h: $(TOP)/src/build/dotnet/$(1)/$(3)/Microsoft.$(9).dll $(LOCAL_MTOUCH) | .libs - $$(Q_GEN) $$(LOCAL_MTOUCH_COMMAND) $$(MTOUCH_VERBOSITY) --runregistrar:$$(abspath $$(basename $$@).m) --sdkroot $$(XCODE_DEVELOPER_ROOT) --sdk $(4) $$< --target-framework .NETCoreApp,Version=$(subst net,,$(DOTNET_TFM)),Profile=$(1) --abi $(2) --reference:$(DOTNET_BCL_DIR)/System.Runtime.dll --reference:$(DOTNET_BCL_DIR)/System.Runtime.InteropServices.dll --rid $(10) + $$(Q_GEN) $$(LOCAL_MTOUCH_COMMAND) $$(MTOUCH_VERBOSITY) --runregistrar:$$(abspath $$(basename $$@).m) --xcode-version $$(XCODE_VERSION) --sdk $(4) $$< --target-framework .NETCoreApp,Version=$(subst net,,$(DOTNET_TFM)),Profile=$(1) --abi $(2) --reference:$(DOTNET_BCL_DIR)/System.Runtime.dll --reference:$(DOTNET_BCL_DIR)/System.Runtime.InteropServices.dll --rid $(10) $$(Q) touch $$(basename $$@).m $$(basename $$@).h .libs/Microsoft.$(9).registrar.$(10).a: .libs/Microsoft.$(9).registrar.$(10).m .libs/Microsoft.$(9).registrar.$(10).h | .libs $$(Q_CC) $$(CLANG) -DDEBUG -g -gdwarf-2 $(6) -stdlib=libc++ -std=c++14 -x objective-c++ -o $$@ -c $$< -Wall -Wno-unguarded-availability-new -I$(TOP)/runtime .libs/Microsoft.$(9).registrar.coreclr.$(10)%m .libs/Microsoft.$(9).registrar.coreclr.$(10)%h: $(TOP)/src/build/dotnet/$(1)/$(3)/Microsoft.$(9).dll $(LOCAL_MTOUCH) | .libs - $$(Q_GEN) $$(LOCAL_MTOUCH_COMMAND) $$(MTOUCH_VERBOSITY) --runregistrar:$$(abspath $$(basename $$@).m) --sdkroot $$(XCODE_DEVELOPER_ROOT) --sdk $(4) $$< --target-framework .NETCoreApp,Version=$(subst net,,$(DOTNET_TFM)),Profile=$(1) --abi $(2) --reference:$(DOTNET_BCL_DIR)/System.Runtime.dll --reference:$(DOTNET_BCL_DIR)/System.Runtime.InteropServices.dll --rid $(10) --xamarin-runtime CoreCLR + $$(Q_GEN) $$(LOCAL_MTOUCH_COMMAND) $$(MTOUCH_VERBOSITY) --runregistrar:$$(abspath $$(basename $$@).m) --xcode-version $$(XCODE_VERSION) --sdk $(4) $$< --target-framework .NETCoreApp,Version=$(subst net,,$(DOTNET_TFM)),Profile=$(1) --abi $(2) --reference:$(DOTNET_BCL_DIR)/System.Runtime.dll --reference:$(DOTNET_BCL_DIR)/System.Runtime.InteropServices.dll --rid $(10) --xamarin-runtime CoreCLR $$(Q) touch $$(basename $$@).m $$(basename $$@).h .libs/Microsoft.$(9).registrar.coreclr.$(10).a: .libs/Microsoft.$(9).registrar.coreclr.$(10).m .libs/Microsoft.$(9).registrar.$(10).h | .libs $$(Q_CC) $$(CLANG) -DDEBUG -g -gdwarf-2 $(6) -stdlib=libc++ -std=c++14 -x objective-c++ -o $$@ -c $$< -Wall -Wno-unguarded-availability-new -I$(TOP)/runtime + +no-xcode-build:: .libs/Microsoft.$(9).registrar.$(10).m .libs/Microsoft.$(9).registrar.$(10).h +no-xcode-build:: .libs/Microsoft.$(9).registrar.coreclr.$(10).m .libs/Microsoft.$(9).registrar.$(10).h endef $(eval $(call RunRegistrar,ios,x86_64,64,$(IOS_SDK_VERSION),iOS,$(iossimulator-x64_CFLAGS),,,iOS,iossimulator-x64)) $(eval $(call RunRegistrar,ios,arm64,64,$(IOS_SDK_VERSION),iOS,$(iossimulator-arm64_CFLAGS),,,iOS,iossimulator-arm64)) @@ -86,12 +89,15 @@ endef $(foreach platform,$(DOTNET_PLATFORMS_MTOUCH),$(foreach rid,$(DOTNET_$(platform)_RUNTIME_IDENTIFIERS),$(eval $(call InstallRegistrar,$(platform),$(rid))))) -ifndef NO_XCODE +ifdef NO_XCODE +dotnet:: no-xcode-build +else dotnet: $(TARGETS_DOTNET) -install-local:: $(TARGETS_DOTNET) -all-local:: $(TARGETS_DOTNET) endif +install-local:: dotnet +all-local:: dotnet + clean-local:: rm -Rf bin obj diff --git a/tools/mtouch/mtouch.cs b/tools/mtouch/mtouch.cs index 21349adc0aaf..42ae6901f1a0 100644 --- a/tools/mtouch/mtouch.cs +++ b/tools/mtouch/mtouch.cs @@ -22,8 +22,6 @@ static int Main2 (string [] args) var os = new OptionSet (); ParseOptions (app, os, args); - ValidateXcode (app, false, false); - app.InitializeCommon (); app.RunRegistrar ();