Showing preview only (3,618K chars total). Download the full file or copy to clipboard to get everything.
Repository: fsprojects/SwaggerProvider
Branch: master
Commit: d30e27de7304
Files: 122
Total size: 3.4 MB
Directory structure:
gitextract_zkbrmfz_/
├── .config/
│ └── dotnet-tools.json
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── ISSUE_TEMPLATE.md
│ ├── aw/
│ │ └── actions-lock.json
│ ├── dependabot.yml
│ └── workflows/
│ ├── docs.yml
│ ├── dotnetcore.yml
│ ├── repo-assist.lock.yml
│ └── repo-assist.md
├── .gitignore
├── AGENTS.md
├── LICENSE.txt
├── README.md
├── SwaggerProvider.TestsAndDocs.sln
├── SwaggerProvider.sln
├── build.cmd
├── build.fsx
├── build.sh
├── docs/
│ ├── .gitignore
│ ├── .vitepress/
│ │ ├── config.mts
│ │ └── theme/
│ │ ├── custom.css
│ │ └── index.ts
│ ├── Customization.md
│ ├── OpenApiClientProvider.md
│ ├── RELEASE_NOTES.md
│ ├── files/
│ │ └── img/
│ │ └── logo.pdn
│ ├── getting-started.md
│ ├── index.md
│ └── package.json
├── global.json
├── paket.dependencies
├── src/
│ ├── Common/
│ │ └── AssemblyInfo.fs
│ ├── SwaggerProvider.DesignTime/
│ │ ├── Caching.fs
│ │ ├── DefinitionCompiler.fs
│ │ ├── OperationCompiler.fs
│ │ ├── Properties/
│ │ │ └── launchSettings.json
│ │ ├── Provider.OpenApiClient.fs
│ │ ├── SwaggerProvider.DesignTime.fsproj
│ │ ├── Utils.fs
│ │ └── paket.references
│ └── SwaggerProvider.Runtime/
│ ├── Exception.fs
│ ├── ProvidedApiClientBase.fs
│ ├── Runtime.fs
│ ├── RuntimeHelpers.fs
│ ├── SwaggerProvider.Runtime.fsproj
│ ├── SwaggerProvider.fsx
│ ├── paket.references
│ └── paket.template
└── tests/
├── SwaggerProvider.ProviderTests/
│ ├── APIs.Guru.FSC.Tests.fs
│ ├── Schemas/
│ │ ├── Instagram.json
│ │ ├── azure-arm-storage.json
│ │ ├── clickmeter.com.json
│ │ ├── github.json
│ │ ├── i0027.json
│ │ ├── issue132.json
│ │ ├── issue173.json
│ │ ├── issue181.yaml
│ │ ├── issue219.yaml
│ │ ├── issue255.yaml
│ │ ├── issue279.json
│ │ ├── my-swashbuckle.json
│ │ ├── nullable-date.yaml
│ │ ├── nullable-parameter-issue261.json
│ │ ├── petstore-v2.json
│ │ ├── petstore.yaml
│ │ ├── slack.json
│ │ ├── swashbuckle.json
│ │ └── unsupported/
│ │ ├── gettyimages.com.json
│ │ └── issue0204.yaml
│ ├── Script.fsx
│ ├── Swagger.I0173.Tests.fs
│ ├── Swagger.I0181.Tests.fs
│ ├── Swagger.I0219.Tests.fs
│ ├── Swagger.I0279.Tests.fs
│ ├── Swagger.NullableDate.Tests.fs
│ ├── Swagger.PetStore.Tests.fs
│ ├── Swagger.SchemaReaderErrors.Tests.fs
│ ├── SwaggerProvider.ProviderTests.fsproj
│ ├── Swashbuckle.CancellationToken.Tests.fs
│ ├── Swashbuckle.FileController.Tests.fs
│ ├── Swashbuckle.NoContentControllers.Tests.fs
│ ├── Swashbuckle.ResourceControllers.Tests.fs
│ ├── Swashbuckle.ReturnControllers.Tests.fs
│ ├── Swashbuckle.ReturnTextControllers.Tests.fs
│ ├── Swashbuckle.SpecialCasesControllers.Tests.fs
│ ├── Swashbuckle.UpdateControllers.Tests.fs
│ ├── paket.references
│ └── thing.fsx
├── SwaggerProvider.Tests/
│ ├── APIs.guru.fs
│ ├── PathResolutionTests.fs
│ ├── RuntimeHelpersTests.fs
│ ├── Schema.ArrayAndMapTypeMappingTests.fs
│ ├── Schema.DefinitionPathTests.fs
│ ├── Schema.OperationCompilationTests.fs
│ ├── Schema.Parser.Tests.fs
│ ├── Schema.TestHelpers.fs
│ ├── Schema.TypeMappingTests.fs
│ ├── Schema.V2SchemaCompilationTests.fs
│ ├── Schema.XmlDocTests.fs
│ ├── SsrfSecurityTests.fs
│ ├── SwaggerProvider.Tests.fsproj
│ ├── UtilsTests.fs
│ └── paket.references
├── Swashbuckle.WebApi.Server/
│ ├── Controllers/
│ │ ├── FileController.fs
│ │ ├── NoContentControllers.fs
│ │ ├── ResourceControllers.fs
│ │ ├── ReturnControllers.fs
│ │ ├── ReturnTextControllers.fs
│ │ ├── SpecialCasesControllers.fs
│ │ ├── Types.fs
│ │ ├── UpdateControllers.fs
│ │ └── ValuesController.fs
│ ├── Program.fs
│ ├── Properties/
│ │ └── launchSettings.json
│ ├── Startup.fs
│ ├── Swashbuckle.WebApi.Server.fsproj
│ ├── app.config
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ └── paket.references
└── test.fsx
================================================
FILE CONTENTS
================================================
================================================
FILE: .config/dotnet-tools.json
================================================
{
"version": 1,
"isRoot": true,
"tools": {
"paket": {
"version": "10.3.1",
"commands": [
"paket"
],
"rollForward": false
},
"dotnet-serve": {
"version": "1.10.194",
"commands": [
"dotnet-serve"
],
"rollForward": false
},
"fantomas": {
"version": "7.0.5",
"commands": [
"fantomas"
],
"rollForward": false
}
}
}
================================================
FILE: .editorconfig
================================================
; EditorConfig helps developers define and maintain consistent
; coding styles between different editors and IDEs.
; For more visit http://editorconfig.org.
root = true
; Choose between lf or rf on "end_of_line" property
[*]
indent_style = space
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[{*.fs,*.fsx}]
indent_size = 4
indent_style = space
max_line_length=150
fsharp_max_function_binding_width=10
fsharp_max_infix_operator_expression=70
fsharp_space_before_parameter=false
fsharp_space_before_lowercase_invocation=false
fsharp_multiline_block_brackets_on_same_column=true
fsharp_experimental_stroustrup_style=true
fsharp_bar_before_discriminated_union_declaration = true
fsharp_keep_max_number_of_blank_lines=3
================================================
FILE: .gitattributes
================================================
# Auto detect text files
* text=auto
# Custom for Visual Studio
*.cs diff=csharp text=auto eol=lf
*.fs diff=csharp text=auto eol=lf
*.fsi diff=csharp text=auto eol=lf
*.fsx diff=csharp text=auto eol=lf
*.sln text eol=crlf merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
.github/workflows/*.lock.yml linguist-generated=true merge=ours
================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
### Description
Please provide a succinct description of your issue.
### Repro steps
Please provide the steps required to reproduce the problem
1. Type provider type definition with parameters
2. Sample schema or relevant schema part
### Expected behavior
Please provide a description of the behavior you expect.
### Actual behavior
Please provide a description of the actual behavior you observe.
### Known workarounds
Please provide a description of any known workarounds.
### Affected Type Providers
- [ ] SwaggerClientProvider
- [ ] OpenApiClientProvider
### Related information
* Operating system
* Branch
* .NET Runtime, CoreCLR or Mono Version
* Performance information, links to performance testing scripts
================================================
FILE: .github/aw/actions-lock.json
================================================
{
"entries": {
"actions/github-script@v9.0.0": {
"repo": "actions/github-script",
"version": "v9.0.0",
"sha": "d746ffe35508b1917358783b479e04febd2b8f71"
},
"github/gh-aw-actions/setup@v0.68.3": {
"repo": "github/gh-aw-actions/setup",
"version": "v0.68.3",
"sha": "ba90f2186d7ad780ec640f364005fa24e797b360"
},
"github/gh-aw/actions/setup@v0.71.1": {
"repo": "github/gh-aw/actions/setup",
"version": "v0.71.1",
"sha": "f01a9d118afa6e306f3645ca31e43f4ea8fb4d22"
}
},
"containers": {
"ghcr.io/github/gh-aw-firewall/agent:0.25.20": {
"image": "ghcr.io/github/gh-aw-firewall/agent:0.25.20",
"digest": "sha256:9161f2415a3306a344aca34dd671ee69f122317e0a512e66dc64c94b9c508682",
"pinned_image": "ghcr.io/github/gh-aw-firewall/agent:0.25.20@sha256:9161f2415a3306a344aca34dd671ee69f122317e0a512e66dc64c94b9c508682"
},
"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20": {
"image": "ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20",
"digest": "sha256:6971639e381e82e45134bcd333181f456df3a52cd6f818a3e3d6de068ff91519",
"pinned_image": "ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20@sha256:6971639e381e82e45134bcd333181f456df3a52cd6f818a3e3d6de068ff91519"
},
"ghcr.io/github/gh-aw-firewall/squid:0.25.20": {
"image": "ghcr.io/github/gh-aw-firewall/squid:0.25.20",
"digest": "sha256:5411d903f73ee597e6a084971c2adef3eb0bd405910df3ed7bf5e3d6bd58a236",
"pinned_image": "ghcr.io/github/gh-aw-firewall/squid:0.25.20@sha256:5411d903f73ee597e6a084971c2adef3eb0bd405910df3ed7bf5e3d6bd58a236"
},
"ghcr.io/github/gh-aw-mcpg:v0.2.19": {
"image": "ghcr.io/github/gh-aw-mcpg:v0.2.19",
"digest": "sha256:44d4d8de7e6c37aaea484eba489940c52df6a0b54078ddcbc9327592d5b3c3dd",
"pinned_image": "ghcr.io/github/gh-aw-mcpg:v0.2.19@sha256:44d4d8de7e6c37aaea484eba489940c52df6a0b54078ddcbc9327592d5b3c3dd"
},
"ghcr.io/github/github-mcp-server:v0.32.0": {
"image": "ghcr.io/github/github-mcp-server:v0.32.0",
"digest": "sha256:2763823c63bcca718ce53850a1d7fcf2f501ec84028394f1b63ce7e9f4f9be28",
"pinned_image": "ghcr.io/github/github-mcp-server:v0.32.0@sha256:2763823c63bcca718ce53850a1d7fcf2f501ec84028394f1b63ce7e9f4f9be28"
},
"node:lts-alpine": {
"image": "node:lts-alpine",
"digest": "sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f",
"pinned_image": "node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"
}
}
}
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "enhancement"
- package-ecosystem: "nuget"
directory: "/.config"
schedule:
interval: "weekly"
labels:
- "enhancement"
================================================
FILE: .github/workflows/docs.yml
================================================
name: Deploy docs to GitHub Pages
on:
push:
branches: [master]
paths:
- 'docs/**'
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 22
- name: Install dependencies
run: npm ci
working-directory: docs
- name: Build docs
run: npm run docs:build
working-directory: docs
- uses: actions/configure-pages@v6
- uses: actions/upload-pages-artifact@v5
with:
path: docs/.vitepress/dist
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
needs: build
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v5
================================================
FILE: .github/workflows/dotnetcore.yml
================================================
name: Build and Test
on:
push:
branches:
- master
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- name: Setup .NET 10.0 SDK
uses: actions/setup-dotnet@v5
with:
dotnet-version: "10.0.x"
- name: Cache NuGet packages
uses: actions/cache@v5
with:
path: |
~/.nuget/packages
~/.local/share/NuGet
%LOCALAPPDATA%\NuGet\v3-cache
key: ${{ runner.os }}-nuget-${{ hashFiles('**/paket.lock') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: Cache .paket directory
uses: actions/cache@v5
with:
path: .paket
key: ${{ runner.os }}-paket-${{ hashFiles('**/paket.lock') }}
restore-keys: |
${{ runner.os }}-paket-
- name: Install local tools
run: dotnet tool restore
- name: Paket Restore
run: dotnet paket restore
- name: Build and Test
run: dotnet fsi build.fsx
================================================
FILE: .github/workflows/repo-assist.lock.yml
================================================
# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"9795d605bdecebc79c8c5cbb8fbf7ffa7b3dfd48ab232f75dcff9e0b162f1b62","compiler_version":"v0.68.3","strict":true,"agent_id":"copilot"}
# 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":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"ba90f2186d7ad780ec640f364005fa24e797b360","version":"v0.68.3"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.20","digest":"sha256:9161f2415a3306a344aca34dd671ee69f122317e0a512e66dc64c94b9c508682","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.25.20@sha256:9161f2415a3306a344aca34dd671ee69f122317e0a512e66dc64c94b9c508682"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20","digest":"sha256:6971639e381e82e45134bcd333181f456df3a52cd6f818a3e3d6de068ff91519","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20@sha256:6971639e381e82e45134bcd333181f456df3a52cd6f818a3e3d6de068ff91519"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.20","digest":"sha256:5411d903f73ee597e6a084971c2adef3eb0bd405910df3ed7bf5e3d6bd58a236","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.25.20@sha256:5411d903f73ee597e6a084971c2adef3eb0bd405910df3ed7bf5e3d6bd58a236"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.19","digest":"sha256:44d4d8de7e6c37aaea484eba489940c52df6a0b54078ddcbc9327592d5b3c3dd","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.2.19@sha256:44d4d8de7e6c37aaea484eba489940c52df6a0b54078ddcbc9327592d5b3c3dd"},{"image":"ghcr.io/github/github-mcp-server:v0.32.0","digest":"sha256:2763823c63bcca718ce53850a1d7fcf2f501ec84028394f1b63ce7e9f4f9be28","pinned_image":"ghcr.io/github/github-mcp-server:v0.32.0@sha256:2763823c63bcca718ce53850a1d7fcf2f501ec84028394f1b63ce7e9f4f9be28"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]}
# ___ _ _
# / _ \ | | (_)
# | |_| | __ _ ___ _ __ | |_ _ ___
# | _ |/ _` |/ _ \ '_ \| __| |/ __|
# | | | | (_| | __/ | | | |_| | (__
# \_| |_/\__, |\___|_| |_|\__|_|\___|
# __/ |
# _ _ |___/
# | | | | / _| |
# | | | | ___ _ __ _ __| |_| | _____ ____
# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___|
# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
#
# This file was automatically generated by gh-aw (v0.68.3). DO NOT EDIT.
#
# To update this file, edit githubnext/agentics/workflows/repo-assist.md@3de4e604a36b5190a1c7dc4719c7341500ba8a95 and run:
# gh aw compile
# Not all edits will cause changes to this file.
#
# For more information: https://github.github.com/gh-aw/introduction/overview/
#
# A friendly repository assistant that runs 2 times a day to support contributors and maintainers.
# Can also be triggered on-demand via '/repo-assist <instructions>' to perform specific tasks.
# - Labels and triages open issues
# - Comments helpfully on open issues to unblock contributors and onboard newcomers
# - Identifies issues that can be fixed and creates draft pull requests with fixes
# - Improves performance, testing, and code quality via PRs
# - Makes engineering investments: dependency updates, CI improvements, tooling
# - Updates its own PRs when CI fails or merge conflicts arise
# - Nudges stale PRs waiting for author response
# - Takes the repository forward with proactive improvements
# - Maintains a persistent memory of work done and what remains
# Always polite, constructive, and mindful of the project's goals.
#
# Source: githubnext/agentics/workflows/repo-assist.md@3de4e604a36b5190a1c7dc4719c7341500ba8a95
#
# Secrets used:
# - COPILOT_GITHUB_TOKEN
# - GH_AW_CI_TRIGGER_TOKEN
# - GH_AW_GITHUB_MCP_SERVER_TOKEN
# - GH_AW_GITHUB_TOKEN
# - GITHUB_TOKEN
#
# Custom actions used:
# - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
# - actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
# - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
# - github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3
#
# Container images used:
# - ghcr.io/github/gh-aw-firewall/agent:0.25.20@sha256:9161f2415a3306a344aca34dd671ee69f122317e0a512e66dc64c94b9c508682
# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20@sha256:6971639e381e82e45134bcd333181f456df3a52cd6f818a3e3d6de068ff91519
# - ghcr.io/github/gh-aw-firewall/squid:0.25.20@sha256:5411d903f73ee597e6a084971c2adef3eb0bd405910df3ed7bf5e3d6bd58a236
# - ghcr.io/github/gh-aw-mcpg:v0.2.19@sha256:44d4d8de7e6c37aaea484eba489940c52df6a0b54078ddcbc9327592d5b3c3dd
# - ghcr.io/github/github-mcp-server:v0.32.0@sha256:2763823c63bcca718ce53850a1d7fcf2f501ec84028394f1b63ce7e9f4f9be28
# - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
name: "Repo Assist"
"on":
discussion:
types:
- created
- edited
discussion_comment:
types:
- created
- edited
issue_comment:
types:
- created
- edited
issues:
types:
- opened
- edited
- reopened
pull_request:
types:
- opened
- edited
- reopened
pull_request_review_comment:
types:
- created
- edited
schedule:
- cron: "46 12 * * *"
workflow_dispatch:
inputs:
aw_context:
default: ""
description: Agent caller context (used internally by Agentic Workflows).
required: false
type: string
permissions: {}
concurrency:
group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number || github.run_id }}"
run-name: "Repo Assist"
jobs:
activation:
needs: pre_activation
if: "needs.pre_activation.outputs.activated == 'true' && ((github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment') && (github.event_name == 'issues' && (startsWith(github.event.issue.body, '/repo-assist ') || startsWith(github.event.issue.body, '/repo-assist\n') || github.event.issue.body == '/repo-assist') || github.event_name == 'issue_comment' && (startsWith(github.event.comment.body, '/repo-assist ') || startsWith(github.event.comment.body, '/repo-assist\n') || github.event.comment.body == '/repo-assist') && github.event.issue.pull_request == null || github.event_name == 'issue_comment' && (startsWith(github.event.comment.body, '/repo-assist ') || startsWith(github.event.comment.body, '/repo-assist\n') || github.event.comment.body == '/repo-assist') && github.event.issue.pull_request != null || github.event_name == 'pull_request_review_comment' && (startsWith(github.event.comment.body, '/repo-assist ') || startsWith(github.event.comment.body, '/repo-assist\n') || github.event.comment.body == '/repo-assist') || github.event_name == 'pull_request' && (startsWith(github.event.pull_request.body, '/repo-assist ') || startsWith(github.event.pull_request.body, '/repo-assist\n') || github.event.pull_request.body == '/repo-assist') || github.event_name == 'discussion' && (startsWith(github.event.discussion.body, '/repo-assist ') || startsWith(github.event.discussion.body, '/repo-assist\n') || github.event.discussion.body == '/repo-assist') || github.event_name == 'discussion_comment' && (startsWith(github.event.comment.body, '/repo-assist ') || startsWith(github.event.comment.body, '/repo-assist\n') || github.event.comment.body == '/repo-assist')) || (!(github.event_name == 'issues')) && (!(github.event_name == 'issue_comment')) && (!(github.event_name == 'pull_request')) && (!(github.event_name == 'pull_request_review_comment')) && (!(github.event_name == 'discussion')) && (!(github.event_name == 'discussion_comment')))"
runs-on: ubuntu-slim
permissions:
actions: read
contents: read
discussions: write
issues: write
pull-requests: write
outputs:
body: ${{ steps.sanitized.outputs.body }}
comment_id: ${{ steps.add-comment.outputs.comment-id }}
comment_repo: ${{ steps.add-comment.outputs.comment-repo }}
comment_url: ${{ steps.add-comment.outputs.comment-url }}
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-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' }}
text: ${{ steps.sanitized.outputs.text }}
title: ${{ steps.sanitized.outputs.title }}
steps:
- name: Setup Scripts
id: setup
uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
trace-id: ${{ needs.pre_activation.outputs.setup-trace-id }}
- 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: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'auto' }}
GH_AW_INFO_VERSION: "1.0.21"
GH_AW_INFO_AGENT_VERSION: "1.0.21"
GH_AW_INFO_CLI_VERSION: "v0.68.3"
GH_AW_INFO_WORKFLOW_NAME: "Repo Assist"
GH_AW_INFO_EXPERIMENTAL: "false"
GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
GH_AW_INFO_STAGED: "false"
GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","dotnet","node","python","rust","java"]'
GH_AW_INFO_FIREWALL_ENABLED: "true"
GH_AW_INFO_AWF_VERSION: "v0.25.20"
GH_AW_INFO_AWMG_VERSION: ""
GH_AW_INFO_FIREWALL_TYPE: "squid"
GH_AW_COMPILED_STRICT: "true"
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
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/generate_aw_info.cjs');
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
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_AW_REACTION: "eyes"
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
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/add_reaction.cjs');
await main();
- name: Validate COPILOT_GITHUB_TOKEN secret
id: validate-secret
run: bash "${RUNNER_TEMP}/gh-aw/actions/validate_multi_secret.sh" COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default
env:
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- name: Checkout .github and .agents folders
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
sparse-checkout: |
.github
.agents
sparse-checkout-cone-mode: true
fetch-depth: 1
- name: Check workflow lock file
id: check-lock-file
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_AW_WORKFLOW_FILE: "repo-assist.lock.yml"
GH_AW_CONTEXT_WORKFLOW_REF: "${{ github.workflow_ref }}"
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/check_workflow_timestamp_api.cjs');
await main();
- name: Check compile-agentic version
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_AW_COMPILED_VERSION: "v0.68.3"
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/check_version_updates.cjs');
await main();
- name: Compute current body text
id: sanitized
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
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/compute_text.cjs');
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
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_AW_WORKFLOW_NAME: "Repo Assist"
GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e Generated by 🌈 {workflow_name}, see [workflow run]({run_url}). [Learn more](https://github.com/githubnext/agentics/blob/main/docs/repo-assist.md).\",\"runStarted\":\"{workflow_name} is processing {event_type}, see [workflow run]({run_url})...\",\"runSuccess\":\"✓ {workflow_name} completed successfully, see [workflow run]({run_url}).\",\"runFailure\":\"✗ {workflow_name} encountered {status}, see [workflow run]({run_url}).\"}"
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/add_workflow_run_comment.cjs');
await main();
- name: Create prompt with built-in context
env:
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl
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_SERVER_URL: ${{ github.server_url }}
GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
GH_AW_IS_PR_COMMENT: ${{ github.event.issue.pull_request && 'true' || '' }}
GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: ${{ steps.sanitized.outputs.text }}
GH_AW_WIKI_NOTE: ${{ '' }}
# poutine:ignore untrusted_checkout_exec
run: |
bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh"
{
cat << 'GH_AW_PROMPT_2095c4ee969b23af_EOF'
<system>
GH_AW_PROMPT_2095c4ee969b23af_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/repo_memory_prompt.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md"
cat << 'GH_AW_PROMPT_2095c4ee969b23af_EOF'
<safe-output-tools>
Tools: add_comment(max:10), create_issue(max:4), update_issue, create_pull_request(max:4), add_labels(max:30), remove_labels(max:5), push_to_pull_request_branch(max:4), missing_tool, missing_data, noop
GH_AW_PROMPT_2095c4ee969b23af_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_push_to_pr_branch.md"
cat << 'GH_AW_PROMPT_2095c4ee969b23af_EOF'
</safe-output-tools>
<github-context>
The following GitHub context information is available for this workflow:
{{#if __GH_AW_GITHUB_ACTOR__ }}
- **actor**: __GH_AW_GITHUB_ACTOR__
{{/if}}
{{#if __GH_AW_GITHUB_REPOSITORY__ }}
- **repository**: __GH_AW_GITHUB_REPOSITORY__
{{/if}}
{{#if __GH_AW_GITHUB_WORKSPACE__ }}
- **workspace**: __GH_AW_GITHUB_WORKSPACE__
{{/if}}
{{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }}
- **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__
{{/if}}
{{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }}
- **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__
{{/if}}
{{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }}
- **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__
{{/if}}
{{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }}
- **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__
{{/if}}
{{#if __GH_AW_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:
- `$GITHUB_WORKSPACE` → `__GH_AW_GITHUB_REPOSITORY__` (cwd) [full history, all branches available as remote-tracking refs] [additional refs fetched: *]
- **Note**: If a branch you need is not in the list above and is not listed as an additional fetched ref, it has NOT been checked out. For private repositories you cannot fetch it without proper authentication. If the branch is required and not available, exit with an error and ask the user to add it to the `fetch:` option of the `checkout:` configuration (e.g., `fetch: ["refs/pulls/open/*"]` for all open PR refs, or `fetch: ["main", "feature/my-branch"]` for specific branches).
</github-context>
GH_AW_PROMPT_2095c4ee969b23af_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md"
if [ "$GITHUB_EVENT_NAME" = "issue_comment" ] && [ -n "$GH_AW_IS_PR_COMMENT" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review_comment" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review" ]; then
cat "${RUNNER_TEMP}/gh-aw/prompts/pr_context_prompt.md"
fi
if [ "$GITHUB_EVENT_NAME" = "issue_comment" ] && [ -n "$GH_AW_IS_PR_COMMENT" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review_comment" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review" ]; then
cat "${RUNNER_TEMP}/gh-aw/prompts/pr_context_push_to_pr_branch_guidance.md"
fi
cat << 'GH_AW_PROMPT_2095c4ee969b23af_EOF'
</system>
{{#runtime-import .github/workflows/repo-assist.md}}
GH_AW_PROMPT_2095c4ee969b23af_EOF
} > "$GH_AW_PROMPT"
- name: Interpolate variables and render templates
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
GH_AW_GITHUB_SERVER_URL: ${{ github.server_url }}
GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: ${{ steps.sanitized.outputs.text }}
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/interpolate_prompt.cjs');
await main();
- name: Substitute placeholders
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
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_SERVER_URL: ${{ github.server_url }}
GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
GH_AW_IS_PR_COMMENT: ${{ github.event.issue.pull_request && 'true' || '' }}
GH_AW_MEMORY_BRANCH_NAME: 'memory/repo-assist'
GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Max File Size**: 10240 bytes (0.01 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n"
GH_AW_MEMORY_DESCRIPTION: ''
GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/'
GH_AW_MEMORY_TARGET_REPO: ' of the current repository'
GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }}
GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND: ${{ needs.pre_activation.outputs.matched_command }}
GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: ${{ steps.sanitized.outputs.text }}
GH_AW_WIKI_NOTE: ''
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io, getOctokit);
const substitutePlaceholders = require('${{ runner.temp }}/gh-aw/actions/substitute_placeholders.cjs');
// Call the substitution function
return await substitutePlaceholders({
file: process.env.GH_AW_PROMPT,
substitutions: {
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_SERVER_URL: process.env.GH_AW_GITHUB_SERVER_URL,
GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE,
GH_AW_IS_PR_COMMENT: process.env.GH_AW_IS_PR_COMMENT,
GH_AW_MEMORY_BRANCH_NAME: process.env.GH_AW_MEMORY_BRANCH_NAME,
GH_AW_MEMORY_CONSTRAINTS: process.env.GH_AW_MEMORY_CONSTRAINTS,
GH_AW_MEMORY_DESCRIPTION: process.env.GH_AW_MEMORY_DESCRIPTION,
GH_AW_MEMORY_DIR: process.env.GH_AW_MEMORY_DIR,
GH_AW_MEMORY_TARGET_REPO: process.env.GH_AW_MEMORY_TARGET_REPO,
GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED,
GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND,
GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: process.env.GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT,
GH_AW_WIKI_NOTE: process.env.GH_AW_WIKI_NOTE
}
});
- name: Validate prompt placeholders
env:
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
# poutine:ignore untrusted_checkout_exec
run: bash "${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh"
- name: Print prompt
env:
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
# poutine:ignore untrusted_checkout_exec
run: bash "${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh"
- name: Upload activation artifact
if: success()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: activation
path: |
/tmp/gh-aw/aw_info.json
/tmp/gh-aw/aw-prompts/prompt.txt
/tmp/gh-aw/github_rate_limits.jsonl
if-no-files-found: ignore
retention-days: 1
agent:
needs: activation
runs-on: ubuntu-latest
permissions: read-all
env:
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
GH_AW_ASSETS_ALLOWED_EXTS: ""
GH_AW_ASSETS_BRANCH: ""
GH_AW_ASSETS_MAX_SIZE_KB: 0
GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
GH_AW_WORKFLOW_ID_SANITIZED: repoassist
outputs:
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 }}
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' }}
model: ${{ needs.activation.outputs.model }}
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-trace-id: ${{ steps.setup.outputs.trace-id }}
steps:
- name: Setup Scripts
id: setup
uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
trace-id: ${{ needs.activation.outputs.setup-trace-id }}
- name: Set runtime paths
id: set-runtime-paths
run: |
{
echo "GH_AW_SAFE_OUTPUTS=${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl"
echo "GH_AW_SAFE_OUTPUTS_CONFIG_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/config.json"
echo "GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json"
} >> "$GITHUB_OUTPUT"
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
fetch-depth: 0
- name: Fetch additional refs
env:
GH_AW_FETCH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
run: |
header=$(printf "x-access-token:%s" "${GH_AW_FETCH_TOKEN}" | base64 -w 0)
git -c "http.extraheader=Authorization: Basic ${header}" fetch origin '+refs/heads/*:refs/remotes/origin/*'
- name: Create gh-aw temp directory
run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh"
- name: Configure gh CLI for GitHub Enterprise
run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh"
env:
GH_TOKEN: ${{ github.token }}
- name: Start DIFC proxy for pre-agent gh calls
env:
GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
GITHUB_SERVER_URL: ${{ github.server_url }}
DIFC_PROXY_POLICY: '{"allow-only":{"min-integrity":"none","repos":"all"}}'
DIFC_PROXY_IMAGE: 'ghcr.io/github/gh-aw-mcpg:v0.2.19'
run: |
bash "${RUNNER_TEMP}/gh-aw/actions/start_difc_proxy.sh"
- name: Set GH_REPO for proxied steps
run: |
echo "GH_REPO=${GITHUB_REPOSITORY}" >> "$GITHUB_ENV"
- env:
GH_TOKEN: ${{ github.token }}
name: Fetch repo data for task weighting
run: "mkdir -p /tmp/gh-aw\n\n# Fetch open issues with labels (up to 500)\ngh issue list --state open --limit 500 --json number,labels > /tmp/gh-aw/issues.json\n\n# Fetch open PRs with titles (up to 200)\ngh pr list --state open --limit 200 --json number,title > /tmp/gh-aw/prs.json\n\n# Compute task weights and select two tasks for this run\npython3 - << 'EOF'\nimport json, random, os\n\nwith open('/tmp/gh-aw/issues.json') as f:\n issues = json.load(f)\nwith open('/tmp/gh-aw/prs.json') as f:\n prs = json.load(f)\n\nopen_issues = len(issues)\nunlabelled = sum(1 for i in issues if not i.get('labels'))\nrepo_assist_prs = sum(1 for p in prs if p['title'].startswith('[Repo Assist]'))\nother_prs = sum(1 for p in prs if not p['title'].startswith('[Repo Assist]'))\n\ntask_names = {\n 1: 'Issue Labelling',\n 2: 'Issue Investigation and Comment',\n 3: 'Issue Investigation and Fix',\n 4: 'Engineering Investments',\n 5: 'Coding Improvements',\n 6: 'Maintain Repo Assist PRs',\n 7: 'Stale PR Nudges',\n 8: 'Performance Improvements',\n 9: 'Testing Improvements',\n 10: 'Take the Repository Forward',\n}\n\nweights = {\n 1: 1 + 3 * unlabelled,\n 2: 3 + 1 * open_issues,\n 3: 3 + 0.7 * open_issues,\n 4: 5 + 0.2 * open_issues,\n 5: 5 + 0.1 * open_issues,\n 6: float(repo_assist_prs),\n 7: 0.1 * other_prs,\n 8: 3 + 0.05 * open_issues,\n 9: 3 + 0.05 * open_issues,\n 10: 3 + 0.05 * open_issues,\n}\n\n# Seed with run ID for reproducibility within a run\nrun_id = int(os.environ.get('GITHUB_RUN_ID', '0'))\nrng = random.Random(run_id)\n\ntask_ids = list(weights.keys())\ntask_weights = [weights[t] for t in task_ids]\n\n# Weighted sample without replacement (pick 2 distinct tasks)\nchosen, seen = [], set()\nfor t in rng.choices(task_ids, weights=task_weights, k=30):\n if t not in seen:\n seen.add(t)\n chosen.append(t)\n if len(chosen) == 2:\n break\n\nprint('=== Repo Assist Task Selection ===')\nprint(f'Open issues : {open_issues}')\nprint(f'Unlabelled issues : {unlabelled}')\nprint(f'Repo Assist PRs : {repo_assist_prs}')\nprint(f'Other open PRs : {other_prs}')\nprint()\nprint('Task weights:')\nfor t, w in weights.items():\n tag = ' <-- SELECTED' if t in chosen else ''\n print(f' Task {t:2d} ({task_names[t]}): weight {w:6.1f}{tag}')\nprint()\nprint(f'Selected tasks for this run: Task {chosen[0]} ({task_names[chosen[0]]}) and Task {chosen[1]} ({task_names[chosen[1]]})')\n\nresult = {\n 'open_issues': open_issues, 'unlabelled_issues': unlabelled,\n 'repo_assist_prs': repo_assist_prs, 'other_prs': other_prs,\n 'task_names': task_names,\n 'weights': {str(k): round(v, 2) for k, v in weights.items()},\n 'selected_tasks': chosen,\n}\nwith open('/tmp/gh-aw/task_selection.json', 'w') as f:\n json.dump(result, f, indent=2)\nEOF\n"
# Repo memory git-based storage configuration from frontmatter processed below
- name: Clone repo-memory branch (default)
env:
GH_TOKEN: ${{ github.token }}
GITHUB_SERVER_URL: ${{ github.server_url }}
BRANCH_NAME: memory/repo-assist
TARGET_REPO: ${{ github.repository }}
MEMORY_DIR: /tmp/gh-aw/repo-memory/default
CREATE_ORPHAN: true
run: bash "${RUNNER_TEMP}/gh-aw/actions/clone_repo_memory_branch.sh"
- name: Configure Git credentials
env:
REPO_NAME: ${{ github.repository }}
SERVER_URL: ${{ github.server_url }}
GITHUB_TOKEN: ${{ github.token }}
run: |
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
git config --global am.keepcr true
# Re-authenticate git with GitHub token
SERVER_URL_STRIPPED="${SERVER_URL#https://}"
git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
echo "Git configured with standard GitHub Actions identity"
- name: Checkout PR branch
id: checkout-pr
if: |
github.event.pull_request || github.event.issue.pull_request
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
with:
github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
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/checkout_pr_branch.cjs');
await main();
- name: Install GitHub Copilot CLI
run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.21
env:
GH_HOST: github.com
- name: Install AWF binary
run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.20
- name: Parse integrity filter lists
id: parse-guard-vars
env:
GH_AW_BLOCKED_USERS_VAR: ${{ vars.GH_AW_GITHUB_BLOCKED_USERS || '' }}
GH_AW_TRUSTED_USERS_VAR: ${{ vars.GH_AW_GITHUB_TRUSTED_USERS || '' }}
GH_AW_APPROVAL_LABELS_VAR: ${{ vars.GH_AW_GITHUB_APPROVAL_LABELS || '' }}
run: bash "${RUNNER_TEMP}/gh-aw/actions/parse_guard_list.sh"
- name: Stop DIFC proxy
if: always()
continue-on-error: true
run: bash "${RUNNER_TEMP}/gh-aw/actions/stop_difc_proxy.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.20@sha256:9161f2415a3306a344aca34dd671ee69f122317e0a512e66dc64c94b9c508682 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20@sha256:6971639e381e82e45134bcd333181f456df3a52cd6f818a3e3d6de068ff91519 ghcr.io/github/gh-aw-firewall/squid:0.25.20@sha256:5411d903f73ee597e6a084971c2adef3eb0bd405910df3ed7bf5e3d6bd58a236 ghcr.io/github/gh-aw-mcpg:v0.2.19@sha256:44d4d8de7e6c37aaea484eba489940c52df6a0b54078ddcbc9327592d5b3c3dd ghcr.io/github/github-mcp-server:v0.32.0@sha256:2763823c63bcca718ce53850a1d7fcf2f501ec84028394f1b63ce7e9f4f9be28 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
- name: Write Safe Outputs Config
run: |
mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
mkdir -p /tmp/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_0438119ce4975251_EOF'
{"add_comment":{"hide_older_comments":true,"max":10,"target":"*"},"add_labels":{"allowed":["bug","enhancement","help wanted","good first issue","spam","off topic","documentation","question","duplicate","wontfix","needs triage","needs investigation","breaking change","performance","security","refactor"],"max":30,"target":"*"},"create_issue":{"labels":["automation","repo-assist"],"max":4,"title_prefix":"[Repo Assist] "},"create_pull_request":{"draft":true,"labels":["automation","repo-assist"],"max":4,"max_patch_size":1024,"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"],"protected_files_policy":"fallback-to-issue","protected_path_prefixes":[".github/",".agents/"],"title_prefix":"[Repo Assist] "},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_repo_memory":{"memories":[{"dir":"/tmp/gh-aw/repo-memory/default","id":"default","max_file_count":100,"max_file_size":10240,"max_patch_size":10240}]},"push_to_pull_request_branch":{"if_no_changes":"warn","max":4,"max_patch_size":1024,"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"],"protected_files_policy":"fallback-to-issue","protected_path_prefixes":[".github/",".agents/"],"target":"*","title_prefix":"[Repo Assist] "},"remove_labels":{"allowed":["bug","enhancement","help wanted","good first issue","spam","off topic","documentation","question","duplicate","wontfix","needs triage","needs investigation","breaking change","performance","security","refactor"],"max":5,"target":"*"},"report_incomplete":{},"update_issue":{"allow_body":true,"max":1,"target":"*","title_prefix":"[Repo Assist] "}}
GH_AW_SAFE_OUTPUTS_CONFIG_0438119ce4975251_EOF
- name: Write Safe Outputs Tools
env:
GH_AW_TOOLS_META_JSON: |
{
"description_suffixes": {
"add_comment": " CONSTRAINTS: Maximum 10 comment(s) can be added. Target: *. Supports reply_to_id for discussion threading.",
"add_labels": " CONSTRAINTS: Maximum 30 label(s) can be added. Only these labels are allowed: [\"bug\" \"enhancement\" \"help wanted\" \"good first issue\" \"spam\" \"off topic\" \"documentation\" \"question\" \"duplicate\" \"wontfix\" \"needs triage\" \"needs investigation\" \"breaking change\" \"performance\" \"security\" \"refactor\"]. Target: *.",
"create_issue": " CONSTRAINTS: Maximum 4 issue(s) can be created. Title will be prefixed with \"[Repo Assist] \". Labels [\"automation\" \"repo-assist\"] will be automatically added.",
"create_pull_request": " CONSTRAINTS: Maximum 4 pull request(s) can be created. Title will be prefixed with \"[Repo Assist] \". Labels [\"automation\" \"repo-assist\"] will be automatically added. PRs will be created as drafts.",
"push_to_pull_request_branch": " CONSTRAINTS: Maximum 4 push(es) can be made. The target pull request title must start with \"[Repo Assist] \".",
"remove_labels": " CONSTRAINTS: Maximum 5 label(s) can be removed. Only these labels can be removed: [bug enhancement help wanted good first issue spam off topic documentation question duplicate wontfix needs triage needs investigation breaking change performance security refactor]. Target: *.",
"update_issue": " CONSTRAINTS: Maximum 1 issue(s) can be updated. Target: *. The target issue title must start with \"[Repo Assist] \"."
},
"repo_params": {},
"dynamic_tools": []
}
GH_AW_VALIDATION_JSON: |
{
"add_comment": {
"defaultMax": 1,
"fields": {
"body": {
"required": true,
"type": "string",
"sanitize": true,
"maxLength": 65000
},
"item_number": {
"issueOrPRNumber": true
},
"reply_to_id": {
"type": "string",
"maxLength": 256
},
"repo": {
"type": "string",
"maxLength": 256
}
}
},
"add_labels": {
"defaultMax": 5,
"fields": {
"item_number": {
"issueNumberOrTemporaryId": true
},
"labels": {
"required": true,
"type": "array",
"itemType": "string",
"itemSanitize": true,
"itemMaxLength": 128
},
"repo": {
"type": "string",
"maxLength": 256
}
}
},
"create_issue": {
"defaultMax": 1,
"fields": {
"body": {
"required": true,
"type": "string",
"sanitize": true,
"maxLength": 65000
},
"labels": {
"type": "array",
"itemType": "string",
"itemSanitize": true,
"itemMaxLength": 128
},
"parent": {
"issueOrPRNumber": true
},
"repo": {
"type": "string",
"maxLength": 256
},
"temporary_id": {
"type": "string"
},
"title": {
"required": true,
"type": "string",
"sanitize": true,
"maxLength": 128
}
}
},
"create_pull_request": {
"defaultMax": 1,
"fields": {
"body": {
"required": true,
"type": "string",
"sanitize": true,
"maxLength": 65000
},
"branch": {
"required": true,
"type": "string",
"sanitize": true,
"maxLength": 256
},
"draft": {
"type": "boolean"
},
"labels": {
"type": "array",
"itemType": "string",
"itemSanitize": true,
"itemMaxLength": 128
},
"repo": {
"type": "string",
"maxLength": 256
},
"title": {
"required": true,
"type": "string",
"sanitize": true,
"maxLength": 128
}
}
},
"missing_data": {
"defaultMax": 20,
"fields": {
"alternatives": {
"type": "string",
"sanitize": true,
"maxLength": 256
},
"context": {
"type": "string",
"sanitize": true,
"maxLength": 256
},
"data_type": {
"type": "string",
"sanitize": true,
"maxLength": 128
},
"reason": {
"type": "string",
"sanitize": true,
"maxLength": 256
}
}
},
"missing_tool": {
"defaultMax": 20,
"fields": {
"alternatives": {
"type": "string",
"sanitize": true,
"maxLength": 512
},
"reason": {
"required": true,
"type": "string",
"sanitize": true,
"maxLength": 256
},
"tool": {
"type": "string",
"sanitize": true,
"maxLength": 128
}
}
},
"noop": {
"defaultMax": 1,
"fields": {
"message": {
"required": true,
"type": "string",
"sanitize": true,
"maxLength": 65000
}
}
},
"push_to_pull_request_branch": {
"defaultMax": 1,
"fields": {
"branch": {
"required": true,
"type": "string",
"sanitize": true,
"maxLength": 256
},
"message": {
"required": true,
"type": "string",
"sanitize": true,
"maxLength": 65000
},
"pull_request_number": {
"issueOrPRNumber": true
}
}
},
"remove_labels": {
"defaultMax": 5,
"fields": {
"item_number": {
"issueNumberOrTemporaryId": true
},
"labels": {
"required": true,
"type": "array",
"itemType": "string",
"itemSanitize": true,
"itemMaxLength": 128
},
"repo": {
"type": "string",
"maxLength": 256
}
}
},
"report_incomplete": {
"defaultMax": 5,
"fields": {
"details": {
"type": "string",
"sanitize": true,
"maxLength": 65000
},
"reason": {
"required": true,
"type": "string",
"sanitize": true,
"maxLength": 1024
}
}
},
"update_issue": {
"defaultMax": 1,
"fields": {
"assignees": {
"type": "array",
"itemType": "string",
"itemSanitize": true,
"itemMaxLength": 39
},
"body": {
"type": "string",
"sanitize": true,
"maxLength": 65000
},
"issue_number": {
"issueOrPRNumber": true
},
"labels": {
"type": "array",
"itemType": "string",
"itemSanitize": true,
"itemMaxLength": 128
},
"milestone": {
"optionalPositiveInteger": true
},
"operation": {
"type": "string",
"enum": [
"replace",
"append",
"prepend",
"replace-island"
]
},
"repo": {
"type": "string",
"maxLength": 256
},
"status": {
"type": "string",
"enum": [
"open",
"closed"
]
},
"title": {
"type": "string",
"sanitize": true,
"maxLength": 128
}
},
"customValidation": "requiresOneOf:status,title,body"
}
}
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
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/generate_safe_outputs_tools.cjs');
await main();
- name: Generate Safe Outputs MCP Server Config
id: safe-outputs-config
run: |
# Generate a secure random API key (360 bits of entropy, 40+ chars)
# Mask immediately to prevent timing vulnerabilities
API_KEY=$(openssl rand -base64 45 | tr -d '/+=')
echo "::add-mask::${API_KEY}"
PORT=3001
# Set outputs for next steps
{
echo "safe_outputs_api_key=${API_KEY}"
echo "safe_outputs_port=${PORT}"
} >> "$GITHUB_OUTPUT"
echo "Safe Outputs MCP server will run on port ${PORT}"
- name: Start Safe Outputs MCP HTTP Server
id: safe-outputs-start
env:
DEBUG: '*'
GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }}
GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }}
GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/tools.json
GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/config.json
GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
run: |
# Environment variables are set above to prevent template injection
export DEBUG
export GH_AW_SAFE_OUTPUTS
export GH_AW_SAFE_OUTPUTS_PORT
export GH_AW_SAFE_OUTPUTS_API_KEY
export GH_AW_SAFE_OUTPUTS_TOOLS_PATH
export GH_AW_SAFE_OUTPUTS_CONFIG_PATH
export GH_AW_MCP_LOG_DIR
bash "${RUNNER_TEMP}/gh-aw/actions/start_safe_outputs_server.sh"
- name: Start MCP Gateway
id: start-mcp-gateway
env:
GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }}
GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }}
GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
run: |
set -eo pipefail
mkdir -p /tmp/gh-aw/mcp-config
# Export gateway environment variables for MCP config and gateway script
export MCP_GATEWAY_PORT="80"
export MCP_GATEWAY_DOMAIN="host.docker.internal"
MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=')
echo "::add-mask::${MCP_GATEWAY_API_KEY}"
export MCP_GATEWAY_API_KEY
export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads"
mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}"
export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288"
export DEBUG="*"
export GH_AW_ENGINE="copilot"
export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -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.2.19'
mkdir -p /home/runner/.copilot
cat << GH_AW_MCP_CONFIG_567b4b2b7203b398_EOF | bash "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh"
{
"mcpServers": {
"github": {
"type": "stdio",
"container": "ghcr.io/github/github-mcp-server:v0.32.0",
"env": {
"GITHUB_HOST": "\${GITHUB_SERVER_URL}",
"GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
"GITHUB_READ_ONLY": "1",
"GITHUB_TOOLSETS": "all"
},
"guard-policies": {
"allow-only": {
"approval-labels": ${{ steps.parse-guard-vars.outputs.approval_labels }},
"blocked-users": ${{ steps.parse-guard-vars.outputs.blocked_users }},
"min-integrity": "none",
"repos": "all",
"trusted-users": ${{ steps.parse-guard-vars.outputs.trusted_users }}
}
}
},
"safeoutputs": {
"type": "http",
"url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT",
"headers": {
"Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}"
},
"guard-policies": {
"write-sink": {
"accept": [
"*"
]
}
}
}
},
"gateway": {
"port": $MCP_GATEWAY_PORT,
"domain": "${MCP_GATEWAY_DOMAIN}",
"apiKey": "${MCP_GATEWAY_API_KEY}",
"payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
}
}
GH_AW_MCP_CONFIG_567b4b2b7203b398_EOF
- name: Download activation artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: activation
path: /tmp/gh-aw
- name: Clean git credentials
continue-on-error: true
run: bash "${RUNNER_TEMP}/gh-aw/actions/clean_git_credentials.sh"
- name: Execute GitHub Copilot CLI
id: agentic_execution
# Copilot CLI tool arguments (sorted):
timeout-minutes: 60
run: |
set -o pipefail
touch /tmp/gh-aw/agent-step-summary.md
(umask 177 && touch /tmp/gh-aw/agent-stdio.log)
# 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 '*.gradle-enterprise.cloud,*.pythonhosted.org,*.vsblob.vsassets.io,adoptium.net,anaconda.org,api.adoptium.net,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.foojay.io,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.nuget.org,api.snapcraft.io,archive.apache.org,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,binstar.org,bootstrap.pypa.io,builds.dotnet.microsoft.com,bun.sh,cdn.azul.com,cdn.jsdelivr.net,central.sonatype.com,ci.dot.net,conda.anaconda.org,conda.binstar.org,crates.io,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,deb.nodesource.com,deno.land,develocity.apache.org,dist.nuget.org,dl.google.com,dlcdn.apache.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,download.eclipse.org,download.java.net,download.oracle.com,downloads.gradle-dn.com,esm.sh,files.pythonhosted.org,ge.spockframework.org,get.pnpm.io,github.com,googleapis.deno.dev,googlechromelabs.github.io,gradle.org,host.docker.internal,index.crates.io,jcenter.bintray.com,jdk.java.net,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,maven-central.storage-download.googleapis.com,maven.apache.org,maven.google.com,maven.oracle.com,maven.pkg.github.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,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,pip.pypa.io,pkgs.dev.azure.com,plugins-artifacts.gradle.org,plugins.gradle.org,ppa.launchpad.net,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.anaconda.com,repo.continuum.io,repo.gradle.org,repo.grails.org,repo.maven.apache.org,repo.spring.io,repo.yarnpkg.com,repo1.maven.org,repository.apache.org,s.symcb.com,s.symcd.com,scans-in.gradle.com,security.ubuntu.com,services.gradle.org,sh.rustup.rs,skimdb.npmjs.com,static.crates.io,static.rust-lang.org,storage.googleapis.com,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.java.com,www.microsoft.com,www.npmjs.com,www.npmjs.org,yarnpkg.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.20 --skip-pull --enable-api-proxy \
-- /bin/bash -c 'node ${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 "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
env:
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }}
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.68.3
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_HEAD_REF: ${{ github.head_ref }}
GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
GITHUB_REF_NAME: ${{ github.ref_name }}
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md
GITHUB_WORKSPACE: ${{ github.workspace }}
GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
XDG_CONFIG_HOME: /home/runner
- name: Detect Copilot errors
id: detect-copilot-errors
if: always()
continue-on-error: true
run: node "${RUNNER_TEMP}/gh-aw/actions/detect_copilot_errors.cjs"
- name: Configure Git credentials
env:
REPO_NAME: ${{ github.repository }}
SERVER_URL: ${{ github.server_url }}
GITHUB_TOKEN: ${{ github.token }}
run: |
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
git config --global am.keepcr true
# Re-authenticate git with GitHub token
SERVER_URL_STRIPPED="${SERVER_URL#https://}"
git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
echo "Git configured with standard GitHub Actions identity"
- name: Copy Copilot session state files to logs
if: always()
continue-on-error: true
run: bash "${RUNNER_TEMP}/gh-aw/actions/copy_copilot_session_state.sh"
- name: Stop MCP Gateway
if: always()
continue-on-error: true
env:
MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}
MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }}
GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }}
run: |
bash "${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh" "$GATEWAY_PID"
- name: Redact secrets in logs
if: always()
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
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/redact_secrets.cjs');
await main();
env:
GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN'
SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Append agent step summary
if: always()
run: bash "${RUNNER_TEMP}/gh-aw/actions/append_agent_step_summary.sh"
- name: Copy Safe Outputs
if: always()
env:
GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
run: |
mkdir -p /tmp/gh-aw
cp "$GH_AW_SAFE_OUTPUTS" /tmp/gh-aw/safeoutputs.jsonl 2>/dev/null || true
- name: Ingest agent output
id: collect_output
if: always()
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
GH_AW_ALLOWED_DOMAINS: "*.gradle-enterprise.cloud,*.pythonhosted.org,*.vsblob.vsassets.io,adoptium.net,anaconda.org,api.adoptium.net,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.foojay.io,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.nuget.org,api.snapcraft.io,archive.apache.org,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,binstar.org,bootstrap.pypa.io,builds.dotnet.microsoft.com,bun.sh,cdn.azul.com,cdn.jsdelivr.net,central.sonatype.com,ci.dot.net,conda.anaconda.org,conda.binstar.org,crates.io,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,deb.nodesource.com,deno.land,develocity.apache.org,dist.nuget.org,dl.google.com,dlcdn.apache.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,download.eclipse.org,download.java.net,download.oracle.com,downloads.gradle-dn.com,esm.sh,files.pythonhosted.org,ge.spockframework.org,get.pnpm.io,github.com,googleapis.deno.dev,googlechromelabs.github.io,gradle.org,host.docker.internal,index.crates.io,jcenter.bintray.com,jdk.java.net,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,maven-central.storage-download.googleapis.com,maven.apache.org,maven.google.com,maven.oracle.com,maven.pkg.github.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,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,pip.pypa.io,pkgs.dev.azure.com,plugins-artifacts.gradle.org,plugins.gradle.org,ppa.launchpad.net,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.anaconda.com,repo.continuum.io,repo.gradle.org,repo.grails.org,repo.maven.apache.org,repo.spring.io,repo.yarnpkg.com,repo1.maven.org,repository.apache.org,s.symcb.com,s.symcd.com,scans-in.gradle.com,security.ubuntu.com,services.gradle.org,sh.rustup.rs,skimdb.npmjs.com,static.crates.io,static.rust-lang.org,storage.googleapis.com,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.java.com,www.microsoft.com,www.npmjs.com,www.npmjs.org,yarnpkg.com"
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_API_URL: ${{ github.api_url }}
GH_AW_COMMAND: repo-assist
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/collect_ndjson_output.cjs');
await main();
- name: Parse agent logs for step summary
if: always()
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/
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_copilot_log.cjs');
await main();
- name: Parse MCP Gateway logs for step summary
if: always()
id: parse-mcp-gateway
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
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_mcp_gateway_log.cjs');
await main();
- name: Print firewall logs
if: always()
continue-on-error: true
env:
AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs
run: |
# Fix permissions on firewall logs 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/logs 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"
else
echo 'AWF binary not installed, skipping firewall log summary'
fi
- name: Parse token usage for step summary
if: always()
continue-on-error: true
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
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: Write agent output placeholder if missing
if: always()
run: |
if [ ! -f /tmp/gh-aw/agent_output.json ]; then
echo '{"items":[]}' > /tmp/gh-aw/agent_output.json
fi
# Upload repo memory as artifacts for push job
- name: Upload repo-memory artifact (default)
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: repo-memory-default
path: /tmp/gh-aw/repo-memory/default
retention-days: 1
if-no-files-found: ignore
- name: Upload agent artifacts
if: always()
continue-on-error: true
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: agent
path: |
/tmp/gh-aw/aw-prompts/prompt.txt
/tmp/gh-aw/sandbox/agent/logs/
/tmp/gh-aw/redacted-urls.log
/tmp/gh-aw/mcp-logs/
/tmp/gh-aw/proxy-logs/
!/tmp/gh-aw/proxy-logs/proxy-tls/
/tmp/gh-aw/agent_usage.json
/tmp/gh-aw/agent-stdio.log
/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/sandbox/firewall/logs/
/tmp/gh-aw/sandbox/firewall/audit/
if-no-files-found: ignore
conclusion:
needs:
- activation
- agent
- detection
- push_repo_memory
- safe_outputs
if: >
always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true' ||
needs.activation.outputs.stale_lock_file_failed == 'true')
runs-on: ubuntu-slim
permissions:
contents: write
discussions: write
issues: write
pull-requests: write
concurrency:
group: "gh-aw-conclusion-repo-assist"
cancel-in-progress: false
outputs:
incomplete_count: ${{ steps.report_incomplete.outputs.incomplete_count }}
noop_message: ${{ steps.noop.outputs.noop_message }}
tools_reported: ${{ steps.missing_tool.outputs.tools_reported }}
total_count: ${{ steps.missing_tool.outputs.total_count }}
steps:
- name: Setup Scripts
id: setup
uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
trace-id: ${{ needs.activation.outputs.setup-trace-id }}
- name: Download agent output artifact
id: download-agent-output
continue-on-error: true
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: agent
path: /tmp/gh-aw/
- name: Setup agent output environment variable
id: setup-agent-output-env
if: steps.download-agent-output.outcome == 'success'
run: |
mkdir -p /tmp/gh-aw/
find "/tmp/gh-aw/" -type f -print
echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
- name: Process no-op messages
id: noop
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_NOOP_MAX: "1"
GH_AW_WORKFLOW_NAME: "Repo Assist"
GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@3de4e604a36b5190a1c7dc4719c7341500ba8a95"
GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/3de4e604a36b5190a1c7dc4719c7341500ba8a95/workflows/repo-assist.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_NOOP_REPORT_AS_ISSUE: "true"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
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/handle_noop_message.cjs');
await main();
- name: Log detection run
id: detection_runs
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Repo Assist"
GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@3de4e604a36b5190a1c7dc4719c7341500ba8a95"
GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/3de4e604a36b5190a1c7dc4719c7341500ba8a95/workflows/repo-assist.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
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/handle_detection_runs.cjs');
await main();
- name: Record missing tool
id: missing_tool
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_MISSING_TOOL_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "Repo Assist"
GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@3de4e604a36b5190a1c7dc4719c7341500ba8a95"
GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/3de4e604a36b5190a1c7dc4719c7341500ba8a95/workflows/repo-assist.md"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
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/missing_tool.cjs');
await main();
- name: Record incomplete
id: report_incomplete
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "Repo Assist"
GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@3de4e604a36b5190a1c7dc4719c7341500ba8a95"
GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/3de4e604a36b5190a1c7dc4719c7341500ba8a95/workflows/repo-assist.md"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
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/report_incomplete_handler.cjs');
await main();
- name: Handle agent failure
id: handle_agent_failure
if: always()
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Repo Assist"
GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@3de4e604a36b5190a1c7dc4719c7341500ba8a95"
GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/3de4e604a36b5190a1c7dc4719c7341500ba8a95/workflows/repo-assist.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_WORKFLOW_ID: "repo-assist"
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_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_CODE_PUSH_FAILURE_ERRORS: ${{ needs.safe_outputs.outputs.code_push_failure_errors }}
GH_AW_CODE_PUSH_FAILURE_COUNT: ${{ needs.safe_outputs.outputs.code_push_failure_count }}
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_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e Generated by 🌈 {workflow_name}, see [workflow run]({run_url}). [Learn more](https://github.com/githubnext/agentics/blob/main/docs/repo-assist.md).\",\"runStarted\":\"{workflow_name} is processing {event_type}, see [workflow run]({run_url})...\",\"runSuccess\":\"✓ {workflow_name} completed successfully, see [workflow run]({run_url}).\",\"runFailure\":\"✗ {workflow_name} encountered {status}, see [workflow run]({run_url}).\"}"
GH_AW_PUSH_REPO_MEMORY_RESULT: ${{ needs.push_repo_memory.result }}
GH_AW_REPO_MEMORY_VALIDATION_FAILED_default: ${{ needs.push_repo_memory.outputs.validation_failed_default }}
GH_AW_REPO_MEMORY_VALIDATION_ERROR_default: ${{ needs.push_repo_memory.outputs.validation_error_default }}
GH_AW_REPO_MEMORY_PATCH_SIZE_EXCEEDED_default: ${{ needs.push_repo_memory.outputs.patch_size_exceeded_default }}
GH_AW_GROUP_REPORTS: "false"
GH_AW_FAILURE_REPORT_AS_ISSUE: "true"
GH_AW_TIMEOUT_MINUTES: "60"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
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/handle_agent_failure.cjs');
await main();
- name: Update reaction comment with completion status
id: conclusion
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }}
GH_AW_COMMENT_REPO: ${{ needs.activation.outputs.comment_repo }}
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_WORKFLOW_NAME: "Repo Assist"
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e Generated by 🌈 {workflow_name}, see [workflow run]({run_url}). [Learn more](https://github.com/githubnext/agentics/blob/main/docs/repo-assist.md).\",\"runStarted\":\"{workflow_name} is processing {event_type}, see [workflow run]({run_url})...\",\"runSuccess\":\"✓ {workflow_name} completed successfully, see [workflow run]({run_url}).\",\"runFailure\":\"✗ {workflow_name} encountered {status}, see [workflow run]({run_url}).\"}"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
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/notify_comment_error.cjs');
await main();
detection:
needs:
- activation
- agent
if: >
always() && needs.agent.result != 'skipped' && (needs.agent.outputs.output_types != '' || needs.agent.outputs.has_patch == 'true')
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }}
detection_reason: ${{ steps.detection_conclusion.outputs.reason }}
detection_success: ${{ steps.detection_conclusion.outputs.success }}
steps:
- name: Setup Scripts
id: setup
uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
trace-id: ${{ needs.activation.outputs.setup-trace-id }}
- name: Download agent output artifact
id: download-agent-output
continue-on-error: true
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: agent
path: /tmp/gh-aw/
- name: Setup agent output environment variable
id: setup-agent-output-env
if: steps.download-agent-output.outcome == 'success'
run: |
mkdir -p /tmp/gh-aw/
find "/tmp/gh-aw/" -type f -print
echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
- name: Checkout repository for patch context
if: needs.agent.outputs.has_patch == 'true'
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# --- Threat Detection ---
- name: Clean stale firewall files from agent artifact
run: |
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.20@sha256:9161f2415a3306a344aca34dd671ee69f122317e0a512e66dc64c94b9c508682 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20@sha256:6971639e381e82e45134bcd333181f456df3a52cd6f818a3e3d6de068ff91519 ghcr.io/github/gh-aw-firewall/squid:0.25.20@sha256:5411d903f73ee597e6a084971c2adef3eb0bd405910df3ed7bf5e3d6bd58a236
- name: Check if detection needed
id: detection_guard
if: always()
env:
OUTPUT_TYPES: ${{ needs.agent.outputs.output_types }}
HAS_PATCH: ${{ needs.agent.outputs.has_patch }}
run: |
if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then
echo "run_detection=true" >> "$GITHUB_OUTPUT"
echo "Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH"
else
echo "run_detection=false" >> "$GITHUB_OUTPUT"
echo "Detection skipped: no agent outputs or patches to analyze"
fi
- name: Clear MCP configuration for detection
if: always() && steps.detection_guard.outputs.run_detection == 'true'
run: |
rm -f /tmp/gh-aw/mcp-config/mcp-servers.json
rm -f /home/runner/.copilot/mcp-config.json
rm -f "$GITHUB_WORKSPACE/.gemini/settings.json"
- name: Prepare threat detection files
if: always() && steps.detection_guard.outputs.run_detection == 'true'
run: |
mkdir -p /tmp/gh-aw/threat-detection/aw-prompts
cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true
cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true
for f in /tmp/gh-aw/aw-*.patch; do
[ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
done
for f in /tmp/gh-aw/aw-*.bundle; do
[ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
done
echo "Prepared threat detection files:"
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@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
WORKFLOW_NAME: "Repo Assist"
WORKFLOW_DESCRIPTION: "A friendly repository assistant that runs 2 times a day to support contributors and maintainers.\nCan also be triggered on-demand via '/repo-assist <instructions>' to perform specific tasks.\n- Labels and triages open issues\n- Comments helpfully on open issues to unblock contributors and onboard newcomers\n- Identifies issues that can be fixed and creates draft pull requests with fixes\n- Improves performance, testing, and code quality via PRs\n- Makes engineering investments: dependency updates, CI improvements, tooling\n- Updates its own PRs when CI fails or merge conflicts arise\n- Nudges stale PRs waiting for author response\n- Takes the repository forward with proactive improvements\n- Maintains a persistent memory of work done and what remains\nAlways polite, constructive, and mindful of the project's goals."
HAS_PATCH: ${{ needs.agent.outputs.has_patch }}
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/setup_threat_detection.cjs');
await main();
- name: Ensure threat-detection directory and log
if: always() && steps.detection_guard.outputs.run_detection == 'true'
run: |
mkdir -p /tmp/gh-aw/threat-detection
touch /tmp/gh-aw/threat-detection/detection.log
- name: Install GitHub Copilot CLI
run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.21
env:
GH_HOST: github.com
- name: Install AWF binary
run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.20
- name: Execute GitHub Copilot CLI
if: always() && steps.detection_guard.outputs.run_detection == 'true'
id: detection_agentic_execution
# Copilot CLI tool arguments (sorted):
timeout-minutes: 20
run: |
set -o pipefail
touch /tmp/gh-aw/agent-step-summary.md
(umask 177 && touch /tmp/gh-aw/threat-detection/detection.log)
# 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 --image-tag 0.25.20 --skip-pull --enable-api-proxy \
-- /bin/bash -c 'node ${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 "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
env:
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }}
GH_AW_PHASE: detection
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_VERSION: v0.68.3
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_HEAD_REF: ${{ github.head_ref }}
GITHUB_REF_NAME: ${{ github.ref_name }}
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md
GITHUB_WORKSPACE: ${{ github.workspace }}
GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
XDG_CONFIG_HOME: /home/runner
- name: Upload threat detection log
if: always() && steps.detection_guard.outputs.run_detection == 'true'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: detection
path: /tmp/gh-aw/threat-detection/detection.log
if-no-files-found: ignore
- name: Parse and conclude threat detection
id: detection_conclusion
if: always()
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }}
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();
pre_activation:
if: "(github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment') && (github.event_name == 'issues' && (startsWith(github.event.issue.body, '/repo-assist ') || startsWith(github.event.issue.body, '/repo-assist\n') || github.event.issue.body == '/repo-assist') || github.event_name == 'issue_comment' && (startsWith(github.event.comment.body, '/repo-assist ') || startsWith(github.event.comment.body, '/repo-assist\n') || github.event.comment.body == '/repo-assist') && github.event.issue.pull_request == null || github.event_name == 'issue_comment' && (startsWith(github.event.comment.body, '/repo-assist ') || startsWith(github.event.comment.body, '/repo-assist\n') || github.event.comment.body == '/repo-assist') && github.event.issue.pull_request != null || github.event_name == 'pull_request_review_comment' && (startsWith(github.event.comment.body, '/repo-assist ') || startsWith(github.event.comment.body, '/repo-assist\n') || github.event.comment.body == '/repo-assist') || github.event_name == 'pull_request' && (startsWith(github.event.pull_request.body, '/repo-assist ') || startsWith(github.event.pull_request.body, '/repo-assist\n') || github.event.pull_request.body == '/repo-assist') || github.event_name == 'discussion' && (startsWith(github.event.discussion.body, '/repo-assist ') || startsWith(github.event.discussion.body, '/repo-assist\n') || github.event.discussion.body == '/repo-assist') || github.event_name == 'discussion_comment' && (startsWith(github.event.comment.body, '/repo-assist ') || startsWith(github.event.comment.body, '/repo-assist\n') || github.event.comment.body == '/repo-assist')) || (!(github.event_name == 'issues')) && (!(github.event_name == 'issue_comment')) && (!(github.event_name == 'pull_request')) && (!(github.event_name == 'pull_request_review_comment')) && (!(github.event_name == 'discussion')) && (!(github.event_name == 'discussion_comment'))"
runs-on: ubuntu-slim
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-trace-id: ${{ steps.setup.outputs.trace-id }}
steps:
- name: Setup Scripts
id: setup
uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
- name: Check team membership for command workflow
id: check_membership
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_AW_REQUIRED_ROLES: "admin,maintainer,write"
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
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/check_membership.cjs');
await main();
- name: Check command position
id: check_command_position
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_AW_COMMANDS: "[\"repo-assist\"]"
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/check_command_position.cjs');
await main();
push_repo_memory:
needs:
- activation
- agent
- detection
if: >
always() && (!cancelled()) && (needs.detection.result == 'success' || needs.detection.result == 'skipped') &&
needs.agent.result != 'skipped'
runs-on: ubuntu-slim
permissions:
contents: write
concurrency:
group: "push-repo-memory-${{ github.repository }}|memory/repo-assist"
cancel-in-progress: false
outputs:
patch_size_exceeded_default: ${{ steps.push_repo_memory_default.outputs.patch_size_exceeded }}
validation_error_default: ${{ steps.push_repo_memory_default.outputs.validation_error }}
validation_failed_default: ${{ steps.push_repo_memory_default.outputs.validation_failed }}
steps:
- name: Setup Scripts
id: setup
uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
trace-id: ${{ needs.activation.outputs.setup-trace-id }}
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
sparse-checkout: .
- name: Configure Git credentials
env:
REPO_NAME: ${{ github.repository }}
SERVER_URL: ${{ github.server_url }}
GITHUB_TOKEN: ${{ github.token }}
run: |
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
git config --global am.keepcr true
# Re-authenticate git with GitHub token
SERVER_URL_STRIPPED="${SERVER_URL#https://}"
git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
echo "Git configured with standard GitHub Actions identity"
- name: Download repo-memory artifact (default)
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
continue-on-error: true
with:
name: repo-memory-default
path: /tmp/gh-aw/repo-memory/default
- name: Push repo-memory changes (default)
id: push_repo_memory_default
if: always()
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_TOKEN: ${{ github.token }}
GITHUB_RUN_ID: ${{ github.run_id }}
GITHUB_SERVER_URL: ${{ github.server_url }}
ARTIFACT_DIR: /tmp/gh-aw/repo-memory/default
MEMORY_ID: default
TARGET_REPO: ${{ github.repository }}
BRANCH_NAME: memory/repo-assist
MAX_FILE_SIZE: 10240
MAX_FILE_COUNT: 100
MAX_PATCH_SIZE: 10240
ALLOWED_EXTENSIONS: '[]'
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/push_repo_memory.cjs');
await main();
safe_outputs:
needs:
- activation
- agent
- detection
if: (!cancelled()) && needs.agent.result != 'skipped' && needs.detection.result == 'success'
runs-on: ubuntu-slim
permissions:
contents: write
discussions: write
issues: write
pull-requests: write
timeout-minutes: 15
env:
GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/repo-assist"
GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }}
GH_AW_ENGINE_ID: "copilot"
GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e Generated by 🌈 {workflow_name}, see [workflow run]({run_url}). [Learn more](https://github.com/githubnext/agentics/blob/main/docs/repo-assist.md).\",\"runStarted\":\"{workflow_name} is processing {event_type}, see [workflow run]({run_url})...\",\"runSuccess\":\"✓ {workflow_name} completed successfully, see [workflow run]({run_url}).\",\"runFailure\":\"✗ {workflow_name} encountered {status}, see [workflow run]({run_url}).\"}"
GH_AW_WORKFLOW_ID: "repo-assist"
GH_AW_WORKFLOW_NAME: "Repo Assist"
GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@3de4e604a36b5190a1c7dc4719c7341500ba8a95"
GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/3de4e604a36b5190a1c7dc4719c7341500ba8a95/workflows/repo-assist.md"
outputs:
code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}
code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}
comment_id: ${{ steps.process_safe_outputs.outputs.comment_id }}
comment_url: ${{ steps.process_safe_outputs.outputs.comment_url }}
create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }}
create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }}
created_issue_number: ${{ steps.process_safe_outputs.outputs.created_issue_number }}
created_issue_url: ${{ steps.process_safe_outputs.outputs.created_issue_url }}
created_pr_number: ${{ steps.process_safe_outputs.outputs.created_pr_number }}
created_pr_url: ${{ steps.process_safe_outputs.outputs.created_pr_url }}
process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }}
process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }}
push_commit_sha: ${{ steps.process_safe_outputs.outputs.push_commit_sha }}
push_commit_url: ${{ steps.process_safe_outputs.outputs.push_commit_url }}
steps:
- name: Setup Scripts
id: setup
uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
trace-id: ${{ needs.activation.outputs.setup-trace-id }}
- name: Download agent output artifact
id: download-agent-output
continue-on-error: true
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: agent
path: /tmp/gh-aw/
- name: Setup agent output environment variable
id: setup-agent-output-env
if: steps.download-agent-output.outcome == 'success'
run: |
mkdir -p /tmp/gh-aw/
find "/tmp/gh-aw/" -type f -print
echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
- name: Download patch artifact
continue-on-error: true
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: agent
path: /tmp/gh-aw/
- 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')
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ github.base_ref || github.event.pull_request.base.ref || github.ref_name || github.event.repository.default_branch }}
token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
persist-credentials: false
fetch-depth: 1
- name: Configure Git credentials
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')
env:
REPO_NAME: ${{ github.repository }}
SERVER_URL: ${{ github.server_url }}
GIT_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
run: |
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
git config --global am.keepcr true
# Re-authenticate git with GitHub token
SERVER_URL_STRIPPED="${SERVER_URL#https://}"
git remote set-url origin "https://x-access-token:${GIT_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
echo "Git configured with standard GitHub Actions identity"
- name: Configure GH_HOST for enterprise compatibility
id: ghes-host-config
shell: bash
run: |
# Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct
# GitHub instance (GHES/GHEC). On github.com this is a harmless no-op.
GH_HOST="${GITHUB_SERVER_URL#https://}"
GH_HOST="${GH_HOST#http://}"
echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV"
- name: Process Safe Outputs
id: process_safe_outputs
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_ALLOWED_DOMAINS: "*.gradle-enterprise.cloud,*.pythonhosted.org,*.vsblob.vsassets.io,adoptium.net,anaconda.org,api.adoptium.net,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.foojay.io,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.nuget.org,api.snapcraft.io,archive.apache.org,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,binstar.org,bootstrap.pypa.io,builds.dotnet.microsoft.com,bun.sh,cdn.azul.com,cdn.jsdelivr.net,central.sonatype.com,ci.dot.net,conda.anaconda.org,conda.binstar.org,crates.io,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,deb.nodesource.com,deno.land,develocity.apache.org,dist.nuget.org,dl.google.com,dlcdn.apache.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,download.eclipse.org,download.java.net,download.oracle.com,downloads.gradle-dn.com,esm.sh,files.pythonhosted.org,ge.spockframework.org,get.pnpm.io,github.com,googleapis.deno.dev,googlechromelabs.github.io,gradle.org,host.docker.internal,index.crates.io,jcenter.bintray.com,jdk.java.net,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,maven-central.storage-download.googleapis.com,maven.apache.org,maven.google.com,maven.oracle.com,maven.pkg.github.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,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,pip.pypa.io,pkgs.dev.azure.com,plugins-artifacts.gradle.org,plugins.gradle.org,ppa.launchpad.net,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.anaconda.com,repo.continuum.io,repo.gradle.org,repo.grails.org,repo.maven.apache.org,repo.spring.io,repo.yarnpkg.com,repo1.maven.org,repository.apache.org,s.symcb.com,s.symcd.com,scans-in.gradle.com,security.ubuntu.com,services.gradle.org,sh.rustup.rs,skimdb.npmjs.com,static.crates.io,static.rust-lang.org,storage.googleapis.com,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.java.com,www.microsoft.com,www.npmjs.com,www.npmjs.org,yarnpkg.com"
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_API_URL: ${{ github.api_url }}
GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"hide_older_comments\":true,\"max\":10,\"target\":\"*\"},\"add_labels\":{\"allowed\":[\"bug\",\"enhancement\",\"help wanted\",\"good first issue\",\"spam\",\"off topic\",\"documentation\",\"question\",\"duplicate\",\"wontfix\",\"needs triage\",\"needs investigation\",\"breaking change\",\"performance\",\"security\",\"refactor\"],\"max\":30,\"target\":\"*\"},\"create_issue\":{\"labels\":[\"automation\",\"repo-assist\"],\"max\":4,\"title_prefix\":\"[Repo Assist] \"},\"create_pull_request\":{\"draft\":true,\"labels\":[\"automation\",\"repo-assist\"],\"max\":4,\"max_patch_size\":1024,\"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\",\"AGENTS.md\"],\"protected_files_policy\":\"fallback-to-issue\",\"protected_path_prefixes\":[\".github/\",\".agents/\"],\"title_prefix\":\"[Repo Assist] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"if_no_changes\":\"warn\",\"max\":4,\"max_patch_size\":1024,\"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\",\"AGENTS.md\"],\"protected_files_policy\":\"fallback-to-issue\",\"protected_path_prefixes\":[\".github/\",\".agents/\"],\"target\":\"*\",\"title_prefix\":\"[Repo Assist] \"},\"remove_labels\":{\"allowed\":[\"bug\",\"enhancement\",\"help wanted\",\"good first issue\",\"spam\",\"off topic\",\"documentation\",\"question\",\"duplicate\",\"wontfix\",\"needs triage\",\"needs investigation\",\"breaking change\",\"performance\",\"security\",\"refactor\"],\"max\":5,\"target\":\"*\"},\"report_incomplete\":{},\"update_issue\":{\"allow_body\":true,\"max\":1,\"target\":\"*\",\"title_prefix\":\"[Repo Assist] \"}}"
GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }}
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
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/safe_output_handler_manager.cjs');
await main();
- name: Upload Safe Outputs Items
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: safe-outputs-items
path: |
/tmp/gh-aw/safe-output-items.jsonl
/tmp/gh-aw/temporary-id-map.json
if-no-files-found: ignore
================================================
FILE: .github/workflows/repo-assist.md
================================================
---
description: |
A friendly repository assistant that runs 2 times a day to support contributors and maintainers.
Can also be triggered on-demand via '/repo-assist <instructions>' to perform specific tasks.
- Labels and triages open issues
- Comments helpfully on open issues to unblock contributors and onboard newcomers
- Identifies issues that can be fixed and creates draft pull requests with fixes
- Improves performance, testing, and code quality via PRs
- Makes engineering investments: dependency updates, CI improvements, tooling
- Updates its own PRs when CI fails or merge conflicts arise
- Nudges stale PRs waiting for author response
- Takes the repository forward with proactive improvements
- Maintains a persistent memory of work done and what remains
Always polite, constructive, and mindful of the project's goals.
on:
schedule: daily
workflow_dispatch:
slash_command:
name: repo-assist
reaction: "eyes"
timeout-minutes: 60
permissions: read-all
network:
allowed:
- defaults
- dotnet
- node
- python
- rust
- java
checkout:
fetch: ["*"] # fetch all remote branches to allow working on PR branches
fetch-depth: 0 # fetch full history
tools:
web-fetch:
github:
toolsets: [all]
allowed-repos: all
min-integrity: none # This workflow is allowed to examine and comment on any issues or PRs
bash: true
repo-memory: true
safe-outputs:
messages:
footer: "> Generated by 🌈 {workflow_name}, see [workflow run]({run_url}). [Learn more](https://github.com/githubnext/agentics/blob/main/docs/repo-assist.md)."
run-started: "{workflow_name} is processing {event_type}, see [workflow run]({run_url})..."
run-success: "✓ {workflow_name} completed successfully, see [workflow run]({run_url})."
run-failure: "✗ {workflow_name} encountered {status}, see [workflow run]({run_url})."
add-comment:
max: 10
target: "*"
hide-older-comments: true
create-pull-request:
draft: true
title-prefix: "[Repo Assist] "
labels: [automation, repo-assist]
protected-files: fallback-to-issue
max: 4
push-to-pull-request-branch:
target: "*"
title-prefix: "[Repo Assist] "
max: 4
protected-files: fallback-to-issue
create-issue:
title-prefix: "[Repo Assist] "
labels: [automation, repo-assist]
max: 4
update-issue:
target: "*"
title-prefix: "[Repo Assist] "
max: 1
add-labels:
allowed: [bug, enhancement, "help wanted", "good first issue", "spam", "off topic", documentation, question, duplicate, wontfix, "needs triage", "needs investigation", "breaking change", performance, security, refactor]
max: 30
target: "*"
remove-labels:
allowed: [bug, enhancement, "help wanted", "good first issue", "spam", "off topic", documentation, question, duplicate, wontfix, "needs triage", "needs investigation", "breaking change", performance, security, refactor]
max: 5
target: "*"
steps:
- name: Fetch repo data for task weighting
env:
GH_TOKEN: ${{ github.token }}
run: |
mkdir -p /tmp/gh-aw
# Fetch open issues with labels (up to 500)
gh issue list --state open --limit 500 --json number,labels > /tmp/gh-aw/issues.json
# Fetch open PRs with titles (up to 200)
gh pr list --state open --limit 200 --json number,title > /tmp/gh-aw/prs.json
# Compute task weights and select two tasks for this run
python3 - << 'EOF'
import json, random, os
with open('/tmp/gh-aw/issues.json') as f:
issues = json.load(f)
with open('/tmp/gh-aw/prs.json') as f:
prs = json.load(f)
open_issues = len(issues)
unlabelled = sum(1 for i in issues if not i.get('labels'))
repo_assist_prs = sum(1 for p in prs if p['title'].startswith('[Repo Assist]'))
other_prs = sum(1 for p in prs if not p['title'].startswith('[Repo Assist]'))
task_names = {
1: 'Issue Labelling',
2: 'Issue Investigation and Comment',
3: 'Issue Investigation and Fix',
4: 'Engineering Investments',
5: 'Coding Improvements',
6: 'Maintain Repo Assist PRs',
7: 'Stale PR Nudges',
8: 'Performance Improvements',
9: 'Testing Improvements',
10: 'Take the Repository Forward',
}
weights = {
1: 1 + 3 * unlabelled,
2: 3 + 1 * open_issues,
3: 3 + 0.7 * open_issues,
4: 5 + 0.2 * open_issues,
5: 5 + 0.1 * open_issues,
6: float(repo_assist_prs),
7: 0.1 * other_prs,
8: 3 + 0.05 * open_issues,
9: 3 + 0.05 * open_issues,
10: 3 + 0.05 * open_issues,
}
# Seed with run ID for reproducibility within a run
run_id = int(os.environ.get('GITHUB_RUN_ID', '0'))
rng = random.Random(run_id)
task_ids = list(weights.keys())
task_weights = [weights[t] for t in task_ids]
# Weighted sample without replacement (pick 2 distinct tasks)
chosen, seen = [], set()
for t in rng.choices(task_ids, weights=task_weights, k=30):
if t not in seen:
seen.add(t)
chosen.append(t)
if len(chosen) == 2:
break
print('=== Repo Assist Task Selection ===')
print(f'Open issues : {open_issues}')
print(f'Unlabelled issues : {unlabelled}')
print(f'Repo Assist PRs : {repo_assist_prs}')
print(f'Other open PRs : {other_prs}')
print()
print('Task weights:')
for t, w in weights.items():
tag = ' <-- SELECTED' if t in chosen else ''
print(f' Task {t:2d} ({task_names[t]}): weight {w:6.1f}{tag}')
print()
print(f'Selected tasks for this run: Task {chosen[0]} ({task_names[chosen[0]]}) and Task {chosen[1]} ({task_names[chosen[1]]})')
result = {
'open_issues': open_issues, 'unlabelled_issues': unlabelled,
'repo_assist_prs': repo_assist_prs, 'other_prs': other_prs,
'task_names': task_names,
'weights': {str(k): round(v, 2) for k, v in weights.items()},
'selected_tasks': chosen,
}
with open('/tmp/gh-aw/task_selection.json', 'w') as f:
json.dump(result, f, indent=2)
EOF
source: githubnext/agentics/workflows/repo-assist.md@3de4e604a36b5190a1c7dc4719c7341500ba8a95
---
# Repo Assist
## Command Mode
Take heed of **instructions**: "${{ steps.sanitized.outputs.text }}"
If these are non-empty (not ""), then you have been triggered via `/repo-assist <instructions>`. Follow the user's instructions instead of the normal scheduled workflow. Focus exclusively on those instructions. Apply all the same guidelines (read AGENTS.md, run formatters/linters/tests, be polite, use AI disclosure). Skip the weighted task selection and Task 11 reporting, and instead directly do what the user requested. If no specific instructions were provided (empty or blank), proceed with the normal scheduled workflow below.
Then exit - do not run the normal workflow after completing the instructions.
## Non-Command Mode
You are Repo Assist for `${{ github.repository }}`. Your job is to support human contributors, help onboard newcomers, identify improvements, and fix bugs by creating pull requests. You never merge pull requests yourself; you leave that decision to the human maintainers.
Always be:
- **Polite and encouraging**: Every contributor deserves respect. Use warm, inclusive language.
- **Concise**: Keep comments focused and actionable. Avoid walls of text.
- **Mindful of project values**: Prioritize **stability**, **correctness**, and **minimal dependencies**. Do not introduce new dependencies without clear justification.
- **Transparent about your nature**: Always clearly identify yourself as Repo Assist, an automated AI assistant. Never pretend to be a human maintainer.
- **Restrained**: When in doubt, do nothing. It is always better to stay silent than to post a redundant, unhelpful, or spammy comment. Human maintainers' attention is precious - do not waste it.
## Memory
Use persistent repo memory to track:
- issues already commented on (with timestamps to detect new human activity)
- fix attempts and outcomes, improvement ideas already submitted, a short to-do list
- a **backlog cursor** so each run continues where the previous one left off
- previously checked off items (checked off by maintainer) in the Monthly Activity Summary to maintain an accurate pending actions list for maintainers
Read memory at the **start** of every run; update it at the **end**.
**Important**: Memory may not be 100% accurate. Issues may have been created, closed, or commented on; PRs may have been created, merged, commented on, or closed since the last run. Always verify memory against current repository state — reviewing recent activity since your last run is wise before acting on stale assumptions.
**Memory backlog tracking**: Your memory may contain notes about issues or PRs that still need attention (e.g., "issues #384, #336 have labels but no comments"). These are **action items for you**, not just informational notes. Each run, check your memory's `notes` field and other tracking fields for any explicitly flagged backlog work, and prioritise acting on it.
## Workflow
Each run, the deterministic pre-step collects live repo data (open issue count, unlabelled issue count, open Repo Assist PRs, other open PRs), computes a **weighted probability** for each task, and selects **two tasks** for this run using a seeded random draw. The weights and selected tasks are printed in the workflow logs. You will find the selection in `/tmp/gh-aw/task_selection.json`.
**Read the task selection**: at the start of your run, read `/tmp/gh-aw/task_selection.json` and confirm the two selected tasks in your opening reasoning. Execute **those two tasks** (plus the mandatory Task 11). If there's really nothing to do for a selected task, do not force yourself to do it - try any other different task instead that looks most useful.
The weighting scheme naturally adapts to repo state:
- When unlabelled issues pile up, Task 1 (labelling) dominates.
- When there are many open issues, Tasks 2 and 3 (commenting and fixing) get more weight.
- As the backlog clears, Tasks 4–10 (engineering, improvements, nudges, forward progress) draw more evenly.
**Repeat-run mode**: When invoked via `gh aw run repo-assist --repeat`, runs occur every 5–10 minutes. Each run is independent — do not skip a run. Always check memory to avoid duplicate work across runs.
**Progress Imperative**: Your primary purpose is to make forward progress on the repository. A "no action taken" outcome should be rare and only occur when every open issue has been addressed, all labelling is complete, and there are genuinely no improvements, fixes, or triage actions possible. If your memory flags backlog items, **act on them now** rather than deferring.
Always do Task 11 (Update Monthly Activity Summary Issue) every run. In all comments and PR descriptions, identify yourself as "Repo Assist". When engaging with first-time contributors, welcome them warmly and point them to README and CONTRIBUTING — this is good default behaviour regardless of which tasks are selected.
### Task 1: Issue Labelling
Process as many unlabelled issues and PRs as possible each run. Resume from memory's backlog cursor.
For each item, apply the best-fitting labels from: `bug`, `enhancement`, `help wanted`, `good first issue`, `documentation`, `question`, `duplicate`, `wontfix`, `spam`, `off topic`, `needs triage`, `needs investigation`, `breaking change`, `performance`, `security`, `refactor`. Remove misapplied labels. Apply multiple where appropriate; skip any you're not confident about. After labelling, post a brief comment if you have something genuinely useful to add.
Update memory with labels applied and cursor position.
### Task 2: Issue Investigation and Comment
1. List open issues sorted by creation date ascending (oldest first). Resume from your memory's backlog cursor; reset when you reach the end.
2. **Prioritise issues that have never received a Repo Assist comment.** Read the issue comments and check memory's `comments_made` field. Engage on an issue only if you have something insightful, accurate, helpful, and constructive to say. Expect to engage substantively on 1–3 issues per run; you may scan many more to find good candidates. Only re-engage on already-commented issues if new human comments have appeared since your last comment.
3. Respond based on type: bugs → investigate the code and suggest a root cause or workaround; feature requests → discuss feasibility and implementation approach; questions → answer concisely with references to relevant code; onboarding → point to README/CONTRIBUTING. Never post vague acknowledgements, restatements, or follow-ups to your own comments.
4. Begin every comment with: `🤖 *This is an automated response from Repo Assist.*`
5. Update memory with comments made and the new cursor position.
### Task 3: Issue Investigation and Fix
**Only attempt fixes you are confident about.** It is fine to work on issues you have previously commented on.
1. Review issues labelled `bug`, `help wanted`, or `good first issue`, plus any identified as fixable during investigation.
2. For each fixable issue:
a. Check memory — skip if you've already tried and the attempt is still open. Never create duplicate PRs.
b. Create a fresh branch off the default branch of the repository: `repo-assist/fix-issue-<N>-<desc>`.
c. Implement a minimal, surgical fix. Do not refactor unrelated code.
d. **Build and test (required)**: do not create a PR if the build fails or tests fail due to your changes. If tests fail due to infrastructure, create the PR but document it.
e. Add a test for the bug if feasible; re-run tests.
f. Create a draft PR with: AI disclosure, `Closes #N`, root cause, fix rationale, trade-offs, and a Test Status section showing build/test outcome.
g. Post a single brief comment on the issue linking to the PR.
3. Update memory with fix attempts and outcomes.
### Task 4: Engineering Investments
Improve the engineering foundations of the repository. Consider:
- **Dependency updates**: Check for outdated dependencies. Prefer minor/patch updates; propose major bumps only with clear benefit. **Bundle Dependabot PRs**: If multiple open Dependabot PRs exist, create a single bundled PR applying all compatible updates. Reference the original PRs so maintainers can close them after merging.
- **CI improvements**: Speed up CI pipelines, fix flaky tests, improve caching, upgrade actions.
- **Tooling and SDK versions**: Update runtime versions, linters, formatters.
- **Build system**: Simplify or modernise the build configuration.
For any change: create a fresh branch `repo-assist/eng-<desc>-<date>`, implement the change, build and test, then create a draft PR with AI disclosure and Test Status section. Update memory with what was checked and when.
### Task 5: Coding Improvements
Study the codebase and make clearly beneficial, low-risk improvements. **Be highly selective — only propose changes with obvious value.**
Good candidates: code clarity and readability, removing dead code, API usability, documentation gaps, reducing duplication.
Check memory for already-submitted ideas; do not re-propose them. Create a fresh branch `repo-assist/improve-<desc>` off the default branch of the repository, implement the improvement, build and test (same requirements as Task 3), then create a draft PR with AI disclosure, rationale, and Test Status section. If not ready to implement, file an issue instead. Update memory.
### Task 6: Maintain Repo Assist PRs
1. List all open PRs with the `[Repo Assist]` title prefix.
2. For each PR: fix CI failures caused by your changes by pushing updates; resolve merge conflicts. If you've retried multiple times without success, comment and leave for human review.
3. Do not push updates for infrastructure-only failures — comment instead.
4. Update memory.
### Task 7: Stale PR Nudges
1. List open non-Repo-Assist PRs not updated in 14+ days.
2. For each (check memory — skip if already nudged): if the PR is waiting on the author, post a single polite comment asking if they need help or want to hand off. Do not comment if the PR is waiting on a maintainer.
3. **Maximum 3 nudges per run.** Update memory.
### Task 8: Performance Improvements
Identify and implement meaningful performance improvements. Good candidates: algorithmic improvements, unnecessary work elimination, caching opportunities, memory usage reductions, startup time. Only propose changes with a clear, measurable benefit. Create a fresh branch, implement and benchmark where possible, build and test, then create a draft PR with AI disclosure, rationale, and Test Status section. Update memory.
### Task 9: Testing Improvements
Improve the quality and coverage of the test suite. Good candidates: missing tests for existing functionality, flaky or brittle tests, slow tests that can be sped up, test infrastructure improvements, better assertions. Avoid adding low-value tests just to inflate coverage. Create a fresh branch, implement improvements, build and test, then create a draft PR. Update memory.
### Task 10: Take the Repository Forward
Proactively move the repository forward. Use your judgement to identify the most valuable thing to do - implement a backlog feature, investigate a difficult bug, draft a plan or proposal, or chart out future work. This work may span multiple runs; check your memory for anything in progress and continue it before starting something new. Record progress and next steps in memory at the end of each run.
### Task 11: Update Monthly Activity Summary Issue (ALWAYS DO THIS TASK IN ADDITION TO OTHERS)
Maintain a single open issue titled `[Repo Assist] Monthly Activity {YYYY}-{MM}` as a rolling summary of all Repo Assist activity for the current month.
1. Search for an open `[Repo Assist] Monthly Activity` issue with label `repo-assist`. If it's for the current month, update it. If for a previous month, close it and create a new one. Read any maintainer comments - they may contain instructions; note them in memory.
2. **Issue body format** - use **exactly** this structure:
```markdown
🤖 *Repo Assist here - I'm an automated AI assistant for this repository.*
## Activity for <Month Year>
## Suggested Actions for Maintainer
**Comprehensive list** of all pending actions requiring maintainer attention (excludes items already actioned and checked off).
- Reread the issue you're updating before you update it - there may be new checkbox adjustments since your last update that require you to adjust the suggested actions.
- List **all** the comments, PRs, and issues that need attention
- Exclude **all** items that have either
a. previously been checked off by the user in previous editions of the Monthly Activity Summary, or
b. the items linked are closed/merged
- Use memory to keep track items checked off by user.
- Be concise - one line per item., repeating the format lines as necessary:
* [ ] **Review PR** #<number>: <summary> - [Review](<link>)
* [ ] **Check comment** #<number>: Repo Assist commented - verify guidance is helpful - [View](<link>)
* [ ] **Merge PR** #<number>: <reason> - [Review](<link>)
* [ ] **Close issue** #<number>: <reason> - [View](<link>)
* [ ] **Close PR** #<number>: <reason> - [View](<link>)
* [ ] **Define goal**: <suggestion> - [Related issue](<link>)
*(If no actions needed, state "No suggested actions at this time.")*
## Future Work for Repo Assist
{Very briefly list future work for Repo Assist}
*(If nothing pending, skip this section.)*
## Run History
### <YYYY-MM-DD HH:MM UTC> - [Run](<https://github.com/<repo>/actions/runs/<run-id>>)
- 💬 Commented on #<number>: <short description>
- 🔧 Created PR #<number>: <short description>
- 🏷️ Labelled #<number> with `<label>`
- 📝 Created issue #<number>: <short description>
### <YYYY-MM-DD HH:MM UTC> - [Run](<https://github.com/<repo>/actions/runs/<run-id>>)
- 🔄 Updated PR #<number>: <short description>
- 💬 Commented on PR #<number>: <short description>
```
3. **Format enforcement (MANDATORY)**:
- Always use the exact format above. If the existing body uses a different format, rewrite it entirely.
- **Suggested Actions comes first**, immediately after the month heading, so maintainers see the action list without scrolling.
- **Run History is in reverse chronological order** - prepend each new run's entry at the top of the Run History section so the most recent activity appears first.
- **Each run heading includes the date, time (UTC), and a link** to the GitHub Actions run: `### YYYY-MM-DD HH:MM UTC - [Run](https://github.com/<repo>/actions/runs/<run-id>)`. Use `${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}` for the current run's link.
- **Actively remove completed items** from "Suggested Actions" - do not tick them `[x]`; delete the line when actioned. The checklist contains only pending items.
- Use `* [ ]` checkboxes in "Suggested Actions". Never use plain bullets there.
4. **Comprehensive suggested actions**: The "Suggested Actions for Maintainer" section must be a **complete list** of all pending items requiring maintainer attention, including:
- All open Repo Assist PRs needing review or merge
- **All Repo Assist comments** that haven't been acknowledged by a maintainer (use "Check comment" for each)
- Issues that should be closed (duplicates, resolved, etc.)
- PRs that should be closed (stale, superseded, etc.)
- Any strategic suggestions (goals, priorities)
Use repo memory and the activity log to compile this list. Include direct links for every item. Keep entries to one line each.
5. Do not update the activity issue if nothing was done in the current run. However, if you conclude "nothing to do", first verify this by checking: (a) Are there any open issues without a Repo Assist comment? (b) Are there issues in your memory flagged for attention? (c) Are there any bugs that could be investigated or fixed? If any of these are true, go back and do that work instead of concluding with no action.
## Guidelines
- **No breaking changes** without maintainer approval via a tracked issue.
- **No new dependencies** without discussion in an issue first.
- **Small, focused PRs** - one concern per PR.
- **Read AGENTS.md first**: before starting work on any pull request, read the repository's `AGENTS.md` file (if present) to understand project-specific conventions, coding standards, and contribution requirements.
- **Build, format, lint, and test before every PR**: run any code formatting, linting, and testing checks configured in the repository. Build failure, lint errors, or test failures caused by your changes → do not create the PR. Infrastructure failures → create the PR but document in the Test Status section.
- **Respect existing style** - match code formatting and naming conventions.
- **AI transparency**: every comment, PR, and issue must include a Repo Assist disclosure with 🤖.
- **Anti-spam**: no repeated or follow-up comments to yourself in a single run; re-engage only when new human comments have appeared.
- **Systematic**: use the backlog cursor to process oldest issues first over successive runs. Do not stop early.
- **Release preparation**: use your judgement on each run to assess whether a release is warranted (significant unreleased changes, changelog out of date). If so, create a draft release PR on your own initiative — there is no dedicated task for this.
- **Quality over quantity**: noise erodes trust. Do nothing rather than add low-value output.
- **Bias toward action**: While avoiding spam, actively seek ways to contribute value within the two selected tasks. A "no action" run should be genuinely exceptional.
================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- Backup*.rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
.paket/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
.ionide
================================================
FILE: AGENTS.md
================================================
## Git Policy
- **NEVER commit or push unless the user explicitly asks you to.** Only create commits when directly requested.
## Build, Test & Lint Commands
- **Build**: `dotnet fake build -t Build` (Release configuration)
- **Format Check**: `dotnet fake build -t CheckFormat` (validates Fantomas formatting)
- **Format**: `dotnet fake build -t Format` (applies Fantomas formatting)
- **All Tests**: `dotnet fake build -t RunTests` (builds + starts test server + runs all tests)
- **Unit Tests Only**: `dotnet build && dotnet tests/SwaggerProvider.Tests/bin/Release/net10.0/SwaggerProvider.Tests.dll`
- **Provider Tests (Integration)**:
1. Build test server: `dotnet build tests/Swashbuckle.WebApi.Server/Swashbuckle.WebApi.Server.fsproj -c Release`
2. Start server in background: `dotnet tests/Swashbuckle.WebApi.Server/bin/Release/net10.0/Swashbuckle.WebApi.Server.dll`
3. Build tests: `dotnet build SwaggerProvider.TestsAndDocs.sln -c Release`
4. Run tests: `dotnet tests/SwaggerProvider.ProviderTests/bin/Release/net10.0/SwaggerProvider.ProviderTests.dll`
- **Single Test**: Run via xunit runner: `dotnet [assembly] [filter]`
## Code Style Guidelines
**Language**: F# (net10.0 target framework)
**Imports & Namespaces**:
- `namespace [Module]` at file start; no `open` statements at module level
- Use `module [Name]` for nested modules
- Open dependencies after namespace declaration (e.g., `open Xunit`, `open FsUnitTyped`)
- Fully qualify internal modules: `SwaggerProvider.Internal.v2.Parser`, `SwaggerProvider.Internal.v3.Compilers`
**Formatting** (via Fantomas, EditorConfig enforced):
- 4-space indents, max 150 char line length
- `fsharp_max_function_binding_width=10`, `fsharp_max_infix_operator_expression=70`
- No space before parameter/lowercase invocation
- Multiline block brackets on same column, Stroustrup style enabled
- Bar before discriminated union declarations, max 3 blank lines
**Naming Conventions**:
- PascalCase for classes, types, modules, public members
- camelCase for local/private bindings, parameters
- Suffix test functions with `Tests` or use attributes like `[<Theory>]`, `[<Fact>]`
**Type Annotations**:
- Explicit return types for public functions (recommended)
- Use type inference for local bindings when obvious
- Generic type parameters: `'a`, `'b` (single quote prefix)
**Error Handling**:
- Use `Result<'T, 'Error>` or `Option<'T>` for fallible operations
- `failwith` or `failwithf` for errors in type providers and compilers
- Task-based async for I/O: `task { }` expressions in tests
- Match failures with `| _ -> ...` or pattern guards with `when`
**File Organization**:
- Tests use Xunit attributes: `[<Theory>]`, `[<Fact>]`, `[<MemberData>]`
- Design-time providers in `src/SwaggerProvider.DesignTime/`, runtime in `src/SwaggerProvider.Runtime/`
- Test schemas organized by OpenAPI version: `tests/.../Schemas/{v2,v3}/`
## Key Patterns
- Type Providers use `ProvidedApiClientBase` and compiler pipeline (DefinitionCompiler, OperationCompiler)
- SSRF protection enabled by default; disable with `SsrfProtection=false` static parameter
- Target net10.0; use implicit async/await (task expressions)
================================================
FILE: LICENSE.txt
================================================
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
================================================
FILE: README.md
================================================
# SwaggerProvider
[](https://www.nuget.org/packages/SwaggerProvider)
[](https://www.nuget.org/packages/SwaggerProvider)
[](http://unlicense.org/)
**SwaggerProvider** is an F# library of generative [Type Providers](https://learn.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/) that auto-generate strongly-typed HTTP client code from [OpenAPI 3.0](https://swagger.io/specification/) and [Swagger 2.0](https://swagger.io/specification/v2/) schemas — no code generation step required.
📚 **Full documentation:** <https://fsprojects.github.io/SwaggerProvider/>
## Quick Start
```fsharp
#r "nuget: SwaggerProvider"
open SwaggerProvider
let [<Literal>] Schema = "https://petstore.swagger.io/v2/swagger.json"
type PetStore = OpenApiClientProvider<Schema>
let client = PetStore.Client()
client.GetInventory() |> Async.AwaitTask |> Async.RunSynchronously
```
## Features
- **Compile-Time Types** — generated at compile time directly from live or local schema files, no separate codegen step needed
- Supports **OpenAPI 3.0** and **Swagger 2.0** schemas in JSON and YAML formats
- **Works Everywhere** — F# scripts, .NET projects, and F# Interactive with full IntelliSense and type-checking
- **SSRF Protection** — blocks HTTP and private IP addresses by default to prevent server-side request forgery attacks
- **CancellationToken Support** — every generated method accepts an optional CancellationToken for cancelling long-running requests
- **Fully Customizable** — bring your own HttpClient, DelegatingHandler, or override JSON serialization
## Installation
```bash
dotnet add package SwaggerProvider
```
## Key Parameters
| Parameter | Default | Description |
|-----------|---------|-------------|
| `Schema` | *(required)* | URL or file path to the OpenAPI/Swagger schema |
| `SsrfProtection` | `true` | Block HTTP and private IPs to prevent SSRF attacks |
| `PreferNullable` | `false` | Use `Nullable<_>` instead of `Option<_>` for optional fields |
| `PreferAsync` | `false` | Generate `Async<'T>` instead of `Task<'T>` |
| `IgnoreControllerPrefix` | `true` | Generate a single client class for all operations |
| `IgnoreOperationId` | `false` | Generate method names from paths instead of operation IDs |
| `IgnoreParseErrors` | `false` | Continue generation even when the parser reports schema warnings |
See the [full documentation](https://fsprojects.github.io/SwaggerProvider/) for more details and examples.
## Maintainer(s)
- [@sergey-tihon](https://github.com/sergey-tihon)
The default maintainer account for projects under "fsprojects" is [@fsprojectsgit](https://github.com/fsprojectsgit) — F# Community Project Incubation Space.
================================================
FILE: SwaggerProvider.TestsAndDocs.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28621.142
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{63297B98-5CED-492C-A5B7-A5B4F73CF142}"
ProjectSection(SolutionItems) = preProject
paket.dependencies = paket.dependencies
paket.lock = paket.lock
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{A6A6AF7D-D6E3-442D-9B1E-58CC91879BE1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{83F16175-43B1-4C90-A1EE-8E351C33435D}"
ProjectSection(SolutionItems) = preProject
docs\tools\generate.fsx = docs\tools\generate.fsx
docs\tools\templates\template.cshtml = docs\tools\templates\template.cshtml
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "content", "content", "{8E6D5255-776D-4B61-85F9-73C37AA1FB9A}"
ProjectSection(SolutionItems) = preProject
docs\content\index.fsx = docs\content\index.fsx
docs\content\tutorial.fsx = docs\content\tutorial.fsx
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{ED8079DD-2B06-4030-9F0F-DC548F98E1C4}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SwaggerProvider.ProviderTests", "tests\SwaggerProvider.ProviderTests\SwaggerProvider.ProviderTests.fsproj", "{F26DFAA6-CB19-46EB-9FBD-F4A4DC46C3F5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{1D6B2F7D-FC4A-499B-B3D1-42A09F42AAAF}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SwaggerProvider.Runtime", "src\SwaggerProvider.Runtime\SwaggerProvider.Runtime.fsproj", "{DC3E73AF-5B15-45AD-B3C5-B3707DCB0F81}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SwaggerProvider.DesignTime", "src\SwaggerProvider.DesignTime\SwaggerProvider.DesignTime.fsproj", "{0598B4A4-3017-493E-8A64-293EAB4CFB95}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CD49F31A-952B-4153-AB76-690091FCE484}"
ProjectSection(SolutionItems) = preProject
global.json = global.json
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F26DFAA6-CB19-46EB-9FBD-F4A4DC46C3F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F26DFAA6-CB19-46EB-9FBD-F4A4DC46C3F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F26DFAA6-CB19-46EB-9FBD-F4A4DC46C3F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F26DFAA6-CB19-46EB-9FBD-F4A4DC46C3F5}.Release|Any CPU.Build.0 = Release|Any CPU
{DC3E73AF-5B15-45AD-B3C5-B3707DCB0F81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DC3E73AF-5B15-45AD-B3C5-B3707DCB0F81}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DC3E73AF-5B15-45AD-B3C5-B3707DCB0F81}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DC3E73AF-5B15-45AD-B3C5-B3707DCB0F81}.Release|Any CPU.Build.0 = Release|Any CPU
{0598B4A4-3017-493E-8A64-293EAB4CFB95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0598B4A4-3017-493E-8A64-293EAB4CFB95}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0598B4A4-3017-493E-8A64-293EAB4CFB95}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0598B4A4-3017-493E-8A64-293EAB4CFB95}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{83F16175-43B1-4C90-A1EE-8E351C33435D} = {A6A6AF7D-D6E3-442D-9B1E-58CC91879BE1}
{8E6D5255-776D-4B61-85F9-73C37AA1FB9A} = {A6A6AF7D-D6E3-442D-9B1E-58CC91879BE1}
{F26DFAA6-CB19-46EB-9FBD-F4A4DC46C3F5} = {ED8079DD-2B06-4030-9F0F-DC548F98E1C4}
{DC3E73AF-5B15-45AD-B3C5-B3707DCB0F81} = {1D6B2F7D-FC4A-499B-B3D1-42A09F42AAAF}
{0598B4A4-3017-493E-8A64-293EAB4CFB95} = {1D6B2F7D-FC4A-499B-B3D1-42A09F42AAAF}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F2D1B446-5EE2-4DDF-83A6-831E733173F4}
EndGlobalSection
EndGlobal
================================================
FILE: SwaggerProvider.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28621.142
MinimumVisualStudioVersion = 10.0.40219.1
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SwaggerProvider.Runtime", "src\SwaggerProvider.Runtime\SwaggerProvider.Runtime.fsproj", "{AD0B2860-9373-4BD9-906D-6D19F2F7DEE9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{04303D28-4592-430A-B4A6-892105A95B22}"
ProjectSection(SolutionItems) = preProject
paket.dependencies = paket.dependencies
paket.lock = paket.lock
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{727FB2BE-A8C5-4537-9C87-7083346E2865}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{3A51AC71-D3EF-46DE-A7F0-E2B46370C6EE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Files", "Solution Files", "{302BCCA4-51B8-475C-9131-548CDC824026}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
build.fsx = build.fsx
global.json = global.json
README.md = README.md
docs\RELEASE_NOTES.md = docs\RELEASE_NOTES.md
EndProjectSection
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SwaggerProvider.DesignTime", "src\SwaggerProvider.DesignTime\SwaggerProvider.DesignTime.fsproj", "{DBE9AA3E-AB4C-4FE3-915B-886CC6E6A88D}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SwaggerProvider.Tests", "tests\SwaggerProvider.Tests\SwaggerProvider.Tests.fsproj", "{358F1AB1-0F38-4D7D-B022-24F4E9EB5673}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Swashbuckle.WebApi.Server", "tests\Swashbuckle.WebApi.Server\Swashbuckle.WebApi.Server.fsproj", "{112C445E-959B-4193-836A-78F36FB9F36E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{BA115E77-63E4-4D9C-AB91-F8FAAD2218D3}"
ProjectSection(SolutionItems) = preProject
.github\workflows\dotnetcore.yml = .github\workflows\dotnetcore.yml
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AD0B2860-9373-4BD9-906D-6D19F2F7DEE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AD0B2860-9373-4BD9-906D-6D19F2F7DEE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AD0B2860-9373-4BD9-906D-6D19F2F7DEE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AD0B2860-9373-4BD9-906D-6D19F2F7DEE9}.Release|Any CPU.Build.0 = Release|Any CPU
{DBE9AA3E-AB4C-4FE3-915B-886CC6E6A88D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DBE9AA3E-AB4C-4FE3-915B-886CC6E6A88D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DBE9AA3E-AB4C-4FE3-915B-886CC6E6A88D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DBE9AA3E-AB4C-4FE3-915B-886CC6E6A88D}.Release|Any CPU.Build.0 = Release|Any CPU
{358F1AB1-0F38-4D7D-B022-24F4E9EB5673}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{358F1AB1-0F38-4D7D-B022-24F4E9EB5673}.Debug|Any CPU.Build.0 = Debug|Any CPU
{358F1AB1-0F38-4D7D-B022-24F4E9EB5673}.Release|Any CPU.ActiveCfg = Release|Any CPU
{358F1AB1-0F38-4D7D-B022-24F4E9EB5673}.Release|Any CPU.Build.0 = Release|Any CPU
{112C445E-959B-4193-836A-78F36FB9F36E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{112C445E-959B-4193-836A-78F36FB9F36E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{112C445E-959B-4193-836A-78F36FB9F36E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{112C445E-959B-4193-836A-78F36FB9F36E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{AD0B2860-9373-4BD9-906D-6D19F2F7DEE9} = {727FB2BE-A8C5-4537-9C87-7083346E2865}
{DBE9AA3E-AB4C-4FE3-915B-886CC6E6A88D} = {727FB2BE-A8C5-4537-9C87-7083346E2865}
{358F1AB1-0F38-4D7D-B022-24F4E9EB5673} = {3A51AC71-D3EF-46DE-A7F0-E2B46370C6EE}
{112C445E-959B-4193-836A-78F36FB9F36E} = {3A51AC71-D3EF-46DE-A7F0-E2B46370C6EE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D1661E43-518D-450C-BB1F-43C008B97BB6}
EndGlobalSection
EndGlobal
================================================
FILE: build.cmd
================================================
@echo off
dotnet tool restore
dotnet paket restore
dotnet fsi build.fsx %*
================================================
FILE: build.fsx
================================================
#r "nuget: Fake.Core.Target"
#r "nuget: Fake.Core.Process"
#r "nuget: Fake.Core.ReleaseNotes"
#r "nuget: Fake.IO.FileSystem"
#r "nuget: Fake.DotNet.Cli"
#r "nuget: Fake.DotNet.AssemblyInfoFile"
#r "nuget: Fake.DotNet.Paket"
#r "nuget: Fake.Tools.Git"
// Boilerplate - https://github.com/fsprojects/FAKE/issues/2719#issuecomment-1470687052
System.Environment.GetCommandLineArgs()
|> Array.skip 2 // skip fsi.exe; build.fsx
|> Array.toList
|> Fake.Core.Context.FakeExecutionContext.Create false __SOURCE_FILE__
|> Fake.Core.Context.RuntimeContext.Fake
|> Fake.Core.Context.setExecutionContext
open Fake
open Fake.Core.TargetOperators
open Fake.Core
open Fake.IO
open Fake.IO.FileSystemOperators
open Fake.IO.Globbing.Operators
open Fake.DotNet
open Fake.Tools
open System.IO
Target.initEnvironment()
// --------------------------------------------------------------------------------------
// Longer description of the project
// (used as a description for NuGet package; line breaks are automatically cleaned up)
let description = "F# Type Provider for Swagger & Open API"
// Git configuration (used for publishing documentation in gh-pages branch)
// The profile where the project is posted
let gitOwner = "fsprojects"
// The name of the project on GitHub
let gitName = "SwaggerProvider"
// --------------------------------------------------------------------------------------
// Read additional information from the release notes document
let release = ReleaseNotes.load "docs/RELEASE_NOTES.md"
// Generate assembly info files with the right version & up-to-date information
Target.create "AssemblyInfo" (fun _ ->
let fileName = "src/Common/AssemblyInfo.fs"
AssemblyInfoFile.createFSharp
fileName
[ AssemblyInfo.Title gitName
AssemblyInfo.Product gitName
AssemblyInfo.Description description
AssemblyInfo.Version release.AssemblyVersion
AssemblyInfo.FileVersion release.AssemblyVersion ])
// --------------------------------------------------------------------------------------
// Clean build results
Target.create "Clean" (fun _ ->
!!"**/**/bin/" |> Shell.cleanDirs
//!! "**/**/obj/" |> Shell.cleanDirs
Shell.cleanDirs [ "bin"; "temp" ]
try
File.Delete("swaggerlog")
with _ ->
())
Target.create "CleanDocs" (fun _ -> Shell.cleanDirs [ "docs/output" ])
// --------------------------------------------------------------------------------------
// Build library & test project
let dotnet cmd args =
let result = DotNet.exec id cmd args
if not result.OK then
failwithf "Failed: %A" result.Errors
Target.create "Build" (fun _ -> dotnet "build" "SwaggerProvider.sln -c Release")
let webApiInputStream = StreamRef.Empty
Target.create "StartServer" (fun _ ->
Target.activateFinal "StopServer"
CreateProcess.fromRawCommandLine "dotnet" "tests/Swashbuckle.WebApi.Server/bin/Release/net10.0/Swashbuckle.WebApi.Server.dll"
|> CreateProcess.withStandardInput(CreatePipe webApiInputStream)
|> Proc.start
|> ignore
// We need delay to guarantee that server is bootstrapped
System.Threading.Thread.Sleep(2000))
Target.createFinal "StopServer" (fun _ ->
// Write something to input stream to stop server
try
webApiInputStream.Value.Write([| 0uy |], 0, 1)
with e ->
printfn "%s" e.Message
//Process.killAllByName "dotnet"
)
Target.create "BuildTests" (fun _ ->
// Explicit restore ensures project.assets.json has all target frameworks before the build.
// Without this, the inner-build restores triggered by Paket.Restore.targets may overwrite
// the assets file with only one TFM, causing NETSDK1005 for the other TFM.
dotnet "restore" "SwaggerProvider.TestsAndDocs.sln"
dotnet "build" "SwaggerProvider.TestsAndDocs.sln -c Release --no-restore")
// --------------------------------------------------------------------------------------
// Run the unit tests using test runner
let runTests assembly =
dotnet $"{assembly}" ""
Target.create "RunUnitTests" (fun _ -> runTests "tests/SwaggerProvider.Tests/bin/Release/net10.0/SwaggerProvider.Tests.dll")
Target.create "RunIntegrationTests" (fun _ -> runTests "tests/SwaggerProvider.ProviderTests/bin/Release/net10.0/SwaggerProvider.ProviderTests.dll")
Target.create "RunTests" ignore
// --------------------------------------------------------------------------------------
// Build a NuGet package
Target.create "NuGet" (fun _ ->
Paket.pack(fun p ->
{ p with
ToolType = ToolType.CreateLocalTool()
OutputPath = "bin"
Version = release.NugetVersion
ReleaseNotes = String.toLines release.Notes }))
Target.create "PublishNuget" (fun _ ->
Paket.push(fun p ->
{ p with
ToolType = ToolType.CreateLocalTool()
WorkingDir = "bin" }))
// --------------------------------------------------------------------------------------
// Generate the documentation
Target.create "BrowseDocs" (fun _ ->
CreateProcess.fromRawCommandLine "npm" "run docs:dev --prefix docs"
|> (Proc.run >> ignore))
// --------------------------------------------------------------------------------------
// Release Scripts
Target.create "Release" (fun _ ->
// not fully converted from FAKE 4
// StageAll ""
// Git.Commit.Commit "" (sprintf "Bump version to %s" release.NugetVersion)
// Branches.push ""
// Branches.tag "" release.NugetVersion
// Branches.pushTag "" "origin" release.NugetVersion
// // release on github
// createClient (getBuildParamOrDefault "github-user" "") (getBuildParamOrDefault "github-pw" "")
// |> createDraft gitOwner gitName release.NugetVersion (release.SemVer.PreRelease <> None) release.Notes
// // TODO: |> uploadFile "PATH_TO_FILE"
// |> releaseDraft
// |> Async.RunSynchronously
// using simplified FAKE 5 release for now
Git.Staging.stageAll ""
Git.Commit.exec "" (sprintf "Bump version to %s" release.NugetVersion)
Git.Branches.push ""
Git.Branches.tag "" release.NugetVersion
Git.Branches.pushTag "" "origin" release.NugetVersion)
Target.create "BuildPackage" ignore
let sourceFiles =
!!"**/*.fs" ++ "**/*.fsx"
-- "packages/**/*.*"
-- "paket-files/**/*.*"
-- ".fake/**/*.*"
-- "**/obj/**/*.*"
-- "**/AssemblyInfo.fs"
Target.create "Format" (fun _ ->
let result =
sourceFiles
|> Seq.map(sprintf "\"%s\"")
|> String.concat " "
|> DotNet.exec id "fantomas"
if not result.OK then
printfn "Errors while formatting all files: %A" result.Messages)
Target.create "CheckFormat" (fun _ ->
let result =
sourceFiles
|> Seq.map(sprintf "\"%s\"")
|> String.concat " "
|> sprintf "%s --check"
|> DotNet.exec id "fantomas"
if result.ExitCode = 0 then
Trace.log "No files need formatting"
elif result.ExitCode = 99 then
failwith "Some files need formatting, run `dotnet fake build -t Format` to format them"
else
Trace.logf "Errors while formatting: %A" result.Errors
failwith "Unknown errors while formatting")
// --------------------------------------------------------------------------------------
// Run all targets by default. Invoke 'build <Target>' to override
Target.create "All" ignore
// https://github.com/fsharp/FAKE/issues/2283
let skipTests = Environment.environVarAsBoolOrDefault "skipTests" false
"Clean"
==> "AssemblyInfo"
==> "CheckFormat"
==> "Build"
==> "RunUnitTests"
==> "StartServer"
==> "BuildTests"
=?> ("RunIntegrationTests", not skipTests)
==> "StopServer"
==> "RunTests"
==> "NuGet"
==> "All"
==> "BuildPackage"
==> "PublishNuget"
==> "Release"
Target.runOrDefault "BuildPackage"
================================================
FILE: build.sh
================================================
#!/bin/bash
if test "$OS" = "Windows_NT"
then
cmd /C build.cmd
else
dotnet tool restore
dotnet paket restore
dotnet fsi build.fsx $@
fi
================================================
FILE: docs/.gitignore
================================================
node_modules/
.vitepress/cache/
.vitepress/dist/
================================================
FILE: docs/.vitepress/config.mts
================================================
import { defineConfig } from "vitepress";
export default defineConfig({
base: "/SwaggerProvider/",
title: "SwaggerProvider",
description: "F# OpenAPI Type Provider",
head: [
["link", { rel: "icon", href: "/files/img/logo.png" }],
[
"link",
{
rel: "stylesheet",
href: "https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500&display=swap",
},
],
],
themeConfig: {
logo: "/files/img/logo.png",
nav: [
{ text: "Home", link: "/" },
{ text: "NuGet", link: "https://www.nuget.org/packages/SwaggerProvider" },
{ text: "GitHub", link: "https://github.com/fsprojects/SwaggerProvider" },
],
sidebar: [
{
text: "Documentation",
items: [
{ text: "Getting Started", link: "/getting-started" },
{ text: "OpenApiClientProvider", link: "/OpenApiClientProvider" },
{ text: "Customization", link: "/Customization" },
{ text: "Release Notes", link: "/RELEASE_NOTES" },
],
},
],
socialLinks: [
{ icon: "github", link: "https://github.com/fsprojects/SwaggerProvider" },
],
search: {
provider: "local",
},
},
});
================================================
FILE: docs/.vitepress/theme/custom.css
================================================
:root {
--vp-font-family-mono: "Fira Code", monospace;
}
.VPHero .image-container .image-bg {
background-image: linear-gradient(135deg, #00c9a7 0%, #1cb5e0 50%, #00d4aa 100%);
border-radius: 50%;
filter: blur(68px);
opacity: 0.6;
}
@supports (font-variation-settings: normal) {
:root {
--vp-font-family-mono: "Fira Code", monospace;
}
}
================================================
FILE: docs/.vitepress/theme/index.ts
================================================
import DefaultTheme from 'vitepress/theme'
import './custom.css'
export default DefaultTheme
================================================
FILE: docs/Customization.md
================================================
# Customization
OpenAPI and Swagger type providers generate one or several API client types (depending on the value of `IgnoreControllerPrefix`).
Each provided API client is a subclass of `ProvidedApiClientBase`, so you can control and customize HTTP calls.
```fsharp
type ProvidedApiClientBase(httpClient: HttpClient) =
member val HttpClient = httpClient with get, set
abstract member Serialize: obj -> string
abstract member Deserialize: string * Type -> obj
```
The snippet shows only the most important parts of `ProvidedApiClientBase`.
The full source includes default `Serialize` and `Deserialize` implementations built on [System.Text.Json](https://learn.microsoft.com/en-us/dotnet/api/system.text.json?view=net-10.0).
**Key features:**
1. You can provide your own `HttpClient` instance during API client construction and fully control request execution (if you do not provide one, the type provider creates a default instance).
2. `Serialize` and `Deserialize` are abstract methods. If the default `JsonSerializerOptions` do not fit your needs, override them and configure `System.Text.Json` as required.
## Request interception
Since you control `HttpClient`, you can use [outgoing request middleware](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests#outgoing-request-middleware), implement your own `DelegatingHandler`, and intercept all HTTP requests generated by the provided API client.
```fsharp {highlight:['8-13','18-20']}
open System
open System.Net.Http
open SwaggerProvider
let [<Literal>] Schema = "https://petstore.swagger.io/v2/swagger.json"
type PetStore = OpenApiClientProvider<Schema, PreferAsync=true>
type LoggingHandler(messageHandler) =
inherit DelegatingHandler(messageHandler)
override __.SendAsync(request, cancellationToken) =
// Put a breakpoint here if you want to debug HTTP calls
printfn "[%A]: %A" request.Method request.RequestUri
base.SendAsync(request, cancellationToken)
[<EntryPoint>]
let main argv =
let baseAddress = Uri("https://petstore.swagger.io/v2/")
let handler1 = new HttpClientHandler (UseCookies = false)
let handler2 = new LoggingHandler(handler1)
use httpClient = new HttpClient(handler2, true, BaseAddress=baseAddress)
let client = PetStore.Client(httpClient)
async {
let pet = PetStore.Pet(Id = Some(24L), Name = "Shani")
do! client.AddPet(pet)
let! myPet = client.GetPetById(24L)
printfn "Waw, my name is %A" myPet.Name
}
|> Async.RunSynchronously
0
```
## Authentication
Authentication is a special case of request interception.
Your custom `DelegatingHandler` is fully responsible for authentication data management (attach an authorization header, add authentication cookies, invalidate tokens, etc.).
```fsharp {highlight:['4-6']}
type AuthHandler(messageHandler) =
inherit DelegatingHandler(messageHandler)
override __.SendAsync(request, cancellationToken) =
// Invalidate your token if it expired
request.Headers.Authorization <-
Headers.AuthenticationHeaderValue("Bearer", "Your OAuth token");
base.SendAsync(request, cancellationToken)
```
If your token does not require invalidation, you can use `HttpClient.DefaultRequestHeaders` to add the `Authorization` header to all requests.
```fsharp {highlight:['4-5']}
let baseAddress = Uri("https://petstore.swagger.io/v2/")
let handler = new HttpClientHandler (UseCookies = false)
use httpClient = new HttpClient(handler, true, BaseAddress=baseAddress)
httpClient.DefaultRequestHeaders.Authorization <-
Headers.AuthenticationHeaderValue("Bearer", "Your OAuth token")
let client = PetStore.Client(httpClient)
```
## Serialization
Serialization is also flexible.
Define your own API client type as a subclass of the generated API client and override `Serialize` and `Deserialize`.
::: info
The serializer is configurable but not replaceable! The Type provider emits types with [JsonPropertyNameAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonpropertynameattribute?view=net-10.0) on properties for seamless serialization.
:::
```fsharp {highlight:['20-28', '33-34']}
open System
open SwaggerProvider
open System.Text.Json
open System.Text.Json.Serialization
let [<Literal>] Schema = "https://petstore.swagger.io/v2/swagger.json"
type PetStore = OpenApiClientProvider<Schema, PreferAsync=true>
let jsonSerializerSettings =
// nuget: System.Text.Json
let settings = JsonSerializerOptions(
//PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
// ...
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
)
// nuget: FSharp.SystemTextJson
JsonFSharpOptions.Default().AddToJsonSerializerOptions settings
settings
type MyApiClient() =
// inherit from provided API client
inherit PetStore.Client()
// Override default implementation of Serialize & Deserialize
override __.Serialize(value:obj): string =
JsonSerializer.Serialize(value, jsonSerializerSettings)
override __.Deserialize(value, retTy:Type): obj =
JsonSerializer.Deserialize(value, retTy, jsonSerializerSettings)
[<EntryPoint>]
let main argv =
// Instantiate your API client
let client = MyApiClient()
async {
let pet = PetStore.Pet(Id = Some(24L), Name = "Shani")
do! client.AddPet(pet)
let! myPet = client.GetPetById(24L)
printfn "Waw, my name is %A" myPet.Name
}
|> Async.RunSynchronously
0
```
================================================
FILE: docs/OpenApiClientProvider.md
================================================
# OpenAPI Client Provider
OpenApiClientProvider is a generative F# Type Provider, built on top of [Microsoft.OpenApi.Readers](https://www.nuget.org/packages/Microsoft.OpenApi.Readers/) schema parser that supports 3.0 and 2.0 schema formats.
```fsharp
open SwaggerProvider
let [<Literal>] Schema = "https://petstore.swagger.io/v2/swagger.json"
type PetStore = OpenApiClientProvider<Schema>
let client = PetStore.Client()
```
## Parameters
`OpenApiClientProvider` supports the following configuration parameters
| Parameter | Description |
|-----------|-------------|
| `Schema` | Url or Path to Swagger schema file. |
| `IgnoreOperationId` | Do not use `operationsId` and generate method names using `path` only. Default value `false`. |
| `IgnoreControllerPrefix` | Do not parse `operationsId` as `<controllerName>_<methodName>` and generate one client class for all operations. Default value `true`. |
| `PreferNullable` | Provide `Nullable<_>` for not required properties, instead of `Option<_>`. Defaults value `false`. |
| `PreferAsync` | Generate async actions of type `Async<'T>` instead of `Task<'T>`. Defaults value `false`. |
| `SsrfProtection` | Enable SSRF protection (blocks HTTP and localhost). Set to `false` for development/testing. Default value `true`. |
| `IgnoreParseErrors` | Continue generating the provider even when the OpenAPI parser reports validation errors (e.g. vendor extensions or non-strictly-compliant schemas). Warnings are printed to stderr. Default value `false`. |
More configuration scenarios are described in [Customization section](/Customization)
## Security (SSRF Protection)
By default, SwaggerProvider blocks HTTP URLs and localhost/private IP addresses to prevent [SSRF attacks](https://owasp.org/www-community/attacks/Server_Side_Request_Forgery).
For **development and testing** with local servers, disable SSRF protection:
```fsharp
// Development: Allow HTTP and localhost
type LocalApi = OpenApiClientProvider<"http://localhost:5000/swagger.json", SsrfProtection=false>
// Production: HTTPS with SSRF protection (default)
type ProdApi = OpenApiClientProvider<"https://api.example.com/swagger.json">
```
**Warning:** Never set `SsrfProtection=false` in production code.
## Non-Strictly-Compliant Schemas (IgnoreParseErrors)
Some OpenAPI schemas generated by tools such as [NSwag](https://github.com/RicoSuter/NSwag) may include extensions or properties that are technically invalid (e.g. `nullable: true` at the parameter level). By default, SwaggerProvider aborts with an error when the Microsoft.OpenApi parser reports such validation errors.
Set `IgnoreParseErrors=true` to continue generating the type provider despite these errors. Validation warnings are printed to stderr so they remain visible:
```fsharp
// NSwag-generated schema with non-standard nullable annotations
type MyApi = OpenApiClientProvider<"https://example.com/swagger.json", IgnoreParseErrors=true>
```
**Note:** Only use `IgnoreParseErrors=true` when you trust the schema source. Suppressing errors may hide genuine schema problems that could affect the generated client.
## CancellationToken Support
Every generated method automatically includes an optional `cancellationToken: CancellationToken` parameter (defaults to `CancellationToken.None`). This allows you to cancel long-running HTTP requests:
```fsharp
open System
open System.Threading
open SwaggerProvider
let [<Literal>] Schema = "https://petstore.swagger.io/v2/swagger.json"
type PetStore = OpenApiClientProvider<Schema>
let client = PetStore.Client()
task {
// Cancel after 5 seconds
use cts = new CancellationTokenSource(TimeSpan.FromSeconds(5.0))
let! pet = client.GetPetById(42L, cancellationToken = cts.Token)
printfn $"Pet: {pet}"
}
|> _.Result
```
## Sample
```fsharp
open System
open System.Net.Http
open SwaggerProvider
let [<Literal>] Schema = "https://petstore.swagger.io/v2/swagger.json"
// By default provided methods return Task<'a>
// and use Option<'a> for optional params
type PetStore = OpenApiClientProvider<Schema>
[<EntryPoint>]
let main argv =
// `UseCookies = false` is required if you use Cookie Parameters
let handler = new HttpClientHandler(UseCookies = false)
// `BaseAddress` uri should end with '/' because TP generates relative URIs
let baseUri = Uri("https://petstore.swagger.io/v2/")
use httpClient = new HttpClient(handler, true, BaseAddress = baseUri)
// You can provide your instance of `HttpClient` to the provided API client
// or change it any time at runtime using `client.HttpClient` property
let client = PetStore.Client(httpClient)
task {
// Create a new instance of the provided type and add to store
let pet = PetStore.Pet(Id = Some(24L), Name = "Shani")
do! client.AddPet(pet)
// Request data back and deserialize to the provided type
let! myPet = client.GetPetById(24L)
printfn "Waw, my name is %A" myPet.Name
}
|> Async.AwaitTask
|> Async.RunSynchronously
0
```
================================================
FILE: docs/RELEASE_NOTES.md
================================================
#### 4.0.0-beta02 - April 18, 2026
- fix: preserve declared properties when schema has both `properties` and `additionalProperties` (#383)
- refactor: `CallAsync` returns `HttpResponseMessage` internally for cleaner response handling (#385)
- eng: remove stale YamlDotNet dependency (removed with v2 parser in #377) (#386)
- test: extend OperationCompiler unit tests (+12 tests for asAsync mode, DELETE/PUT, header params) (#380)
- test: add coverage for cookie params, text/plain response, and default response (+6 tests) (#386)
- docs: update homepage README for v4.0 (remove SwaggerClientProvider references, update targets) (#379)
- docs: improve VitePress site — fix badges, flatten nav, dark theme, add features table (#382)
- ci: bump actions/configure-pages 5→6, deploy-pages 4→5, setup-node 4→6, upload-artifact 7.0.0→7.0.1
#### 4.0.0-beta01 - April 14, 2026
- BREAKING: remove SwaggerClientProvider and v2 compiler, simplify folder structure (#377)
- BREAKING: wrap optional scalar reference types in Option\<T\> (#122) (#357)
- feat: resolve oneOf/anyOf with single $ref to referenced type (#375)
- fix: publish portable PDB debug symbols to NuGet package (#361)
- perf: cache MethodInfo for asyncCast/taskCast to avoid repeated reflection (#374)
- perf: cache property name/metadata lookups in getPropertyValues (#373)
- perf: cache reflection lookups and avoid double seq materialisation (#378)
- docs: improve README with license badge, overview, quick start, and features table (#360)
- test: add DefinitionPath.Parse unit tests and PreferNullable coverage (#370)
- test: extend RuntimeHelpers unit-test coverage (#363)
- eng: add Dependabot for GitHub Actions + v3 OperationCompiler unit tests (#364)
- ci: bump actions/checkout, actions/cache, actions/setup-dotnet, actions/upload-artifact, actions/github-script, github/gh-aw-actions
#### 3.2.0 - April 6, 2026
- feat: add CancellationToken support to OpenApiClientProvider generated methods (closes #212) (#336)
- fix: map `format:date` to `DateOnly` on .NET 6+ targets (closes #240) (#321)
- fix: throw OpenApiException for undocumented HTTP error codes (#354)
- improve: enrich XML documentation for generated API methods (#349)
- improve: add allowed enum values to generated property XmlDoc comments (#353)
- perf: reduce DLL-emit time for large schemas (shared ToString helper + Dictionary lookup) (#356)
- perf: update FSharp.TypeProviders.SDK (O(n^2) to O(n) ILMethodDefs) (#355)
- test: add v3 array/map type-mapping tests and v2 schema compilation tests (#351)
- test: add $ref primitive-type alias tests for v3 DefinitionCompiler (closes #335) (#342)
- hk: update TP SDK and OpenApi reader
#### 3.1.0 - Mar 22, 2026
- feat: Add `IgnoreParseErrors` parameter to OpenApiClientProvider (#300)
- feat: Add `SchemaReaderErrors` property to OpenApiClientProvider (fixes #160) (#327)
- fix: include response body in OpenApiException message (closes #250) (#324)
- fix: unwrap F# `Option<T>` in \`toParam\` for header/path/cookie parameters (closes #140) (#322)
- fix: 2xx response handling in v2 and v3 OperationCompilers (#313)
- fix: `$0` in path parameter values treated as regex back-reference (#310)
- fix: Option types in form data not being unwrapped (issue #214) (#298)
- perf: avoid redundant cache invalidation timers in GetOrAdd (#318)
- perf: increase type provider cache timeout from 30s to 5 minutes (#329)
- hk: update FSharp.TypeProviders.SDK (enum custom attribute bug fix) (#330)
- test: add v3 DefinitionCompiler type-mapping unit tests (#331)
- test: add UniqueNameGenerator unit tests (#319)
- test: add unit tests for RuntimeHelpers module (#295)
- ci: add concurrency group to CI workflow to cancel redundant builds (#309)
#### 3.0.0 - Mar 1, 2026
- feat: Microsoft.OpenApi v2.x with OpenAPI v3.1 Support
- feat: Server-Side Request Forgery (SSRF) protection for IP V4 (#271) and V6 (#272)
- feat: handle text/plain payload types (#276)
- fix: removed dependency on Microsoft.OpenApi.Readers
- fix: error messages when `operationId` is not provided (minimal api) (#277)
- feat: include TP config information in cache key (#283)
- feat: add windows-latest ci (#282)
- feat: Handle allOf with single reference (#284)
- fix: nullable date deserialization for OpenAPI v3 schemas (#287)
- docs: the Serialization documentation to mention use of System.Text.Json rather than Newtonsoft.Json (#288)
- docs: Remove note about TaskBuilder.fs from the OpenApiClientProvider docs (#285)
- feat: Set the "Accept" request header to the specified type (#290)
- feat: Specify a Content-Type header on stream type requests when the payload type is known (#292)
- hk: dependencies update
#### 2.3.2 - Oct 11, 2025
- Added support for `text/*` media type (#270) by @spaasis
#### 2.3.1 - May 13, 2025
- Performance improvement: ProvidedTypes update to the most recent version (#267)
#### 2.3.0 - May 10, 2025
- Added .NET 8 runtime, updated Microsoft.OpenApi (#265)
#### 2.2.3 - Mar 11, 2025
- Update ProvidedTypes.fs to latest version of FSharp.TypeProvider.SDK (#262)
#### 2.2.2 - Jan 23, 2025
- Improvement of design-time error handling (#259)
#### 2.2.1 - Jan 16, 2025
- Added allOf properties to the schema definition (#256)
- Update TypeProvider SDK (#257)
#### 2.2.0 - Jan 6, 2025
- hk: build with .NET 9
- hk: Dependencies update
#### 2.1.3 - Sep 8, 2024
- hk: Dependencies update
#### 2.1.2 - Jun 3, 2024
- fix: Support DateTime/DateTimeOffset as required query parameter, using round-trip format (#244)
- hk: Dependencies update
#### 2.1.1 - Apr 8, 2024
- Minor dependency updates
#### 2.1.0 - Mar 14, 2024
- Build and test with .NET 8.0
#### 2.0.1 - Mar 12, 2024
- fix: update ProvidedTypes.fs (#235)
- FSharp.Data utilities update (#238)
- Updated custom serialization example to SwaggerProvider 2.0 (#239)
#### 2.0.0 - Nov 08, 2023
- F# 6 task{} instead of async{} under thee hood - [#200](https://github.com/fsprojects/SwaggerProvider/pull/200)
- BREAKING: `ProvidedApiClientBase.CallAsync` returns `task` instead of `async`
- BREAKING: `task` CE wrap all exceptions in `AggregateException` (with `OpenApiException` inside)
- Model enums as `string`, `int32` or `boolean` (Fixed [#186](https://github.com/fsprojects/SwaggerProvider/issues/186) )
- Add `Accept` header to all request (Fixed [#196](https://github.com/fsprojects/SwaggerProvider/issues/196))
- Supported requests with `octet-stream` body content [#203](https://github.com/fsprojects/SwaggerProvider/pull/203)
- Added missing properties to OpenApiException [#222](https://github.com/fsprojects/SwaggerProvider/pull/222)
- Changed raise to calling Reraise() extension method to preserve the call stack [#230](https://github.com/fsprojects/SwaggerProvider/pull/230)
- Microsoft.OpenApi (1.6.10)
- FSharp.SystemTextJson (1.2.42)
- Removed the `System.Net.Http` dependency (#221)
- fix: accept "default" as "ok response" fallback (#223)
- Minor performance tweaks (#233)
#### 1.0.2 - Jul 10, 2022
- SharpYaml 2.0.0
- Format code using Fantomas
#### 1.0.1 - Jun 25, 2022
- Dependencies update
#### 1.0.0 - Apr 17, 2022
- Target .NET 6
- Microsoft.OpenApi v1.3.1
- Migration to System.Text.Json [#176](https://github.com/fsprojects/SwaggerProvider/pull/176)
- Fix for 'FS3033: Payload is not supported' [#181](https://github.com/fsprojects/SwaggerProvider/issues/181)
- Drop `net46` support
- Dependencies update
#### 0.12.1 - Apr 9, 2022
- Correctly serialize Guid [] as query parameter [#192](https://github.com/fsprojects/SwaggerProvider/pull/192)
#### 0.12.0 - Dec 22, 2020
- OpenApiProvider: Dictionary support [#174](https://github.com/fsprojects/SwaggerProvider/pull/174)
#### 0.11.0 - Dec 13, 2020
- Relative path fix [#171](https://github.com/fsprojects/SwaggerProvider/pull/171)
- DateTime formatted as round-trip [#170](https://github.com/fsprojects/SwaggerProvider/pull/170)
#### 0.10.7 - July 15, 2020
- Avoid NullReferenceException on rare case that response is nothing. [#162](https://github.com/fsprojects/SwaggerProvider/pull/162)
- Dependencies update
#### 0.10.6 - June 8, 2020
- WebException handling [#161](https://github.com/fsprojects/SwaggerProvider/pull/161)
#### 0.10.5 - June 4, 2020
- Cache, yet one more fix... [#158](https://github.com/fsprojects/SwaggerProvider/pull/158)
#### 0.10.4 - May 31, 2020
- Cache fix part 2 [#155](https://github.com/fsprojects/SwaggerProvider/pull/155)
#### 0.10.3 - May 30, 2020
- Fixed caching [#153](https://github.com/fsprojects/SwaggerProvider/pull/153)
- Dependencies update [#154](https://github.com/fsprojects/SwaggerProvider/pull/154)
#### 0.10.2 - April 5, 2020
- Caching update [#144](https://github.com/fsprojects/SwaggerProvider/pull/144)
- Better autocomplete in IDEs
#### 0.10.1 - April 5, 2020
- Dependencies update [#143](https://github.com/fsprojects/SwaggerProvider/pull/143)
#### 0.10.0 - December 8, 2019
- OpenApiClientProvider
- .NET Core 3.1 support
#### 0.10.0-beta13 - December 8, 2019
- UUID/Guid support [#138](https://github.com/fsprojects/SwaggerProvider/issues/138)
#### 0.10.0-beta12 - November 19, 2019
- Fixed null reference for schemas without Components definitions
#### 0.10.0-beta11 - November 10, 2019
- Delete method incorrectly cased [#120](https://github.com/fsprojects/SwaggerProvider/issues/120)
- File handling - upload/download files as `IO.Stream` [#131](https://github.com/fsprojects/SwaggerProvider/pull/131)
- DateTimeOffset as a default `date-time` type [#133](https://github.com/fsprojects/SwaggerProvider/pull/133)
- Custom OpenApiException instead of HttpRequestException [134](https://github.com/fsprojects/SwaggerProvider/pull/134)
#### 0.10.0-beta10 - November 6, 2019
- Support REST convention with pluralized entities in mode with IgnoreOperationId=true [#121](https://github.com/fsprojects/SwaggerProvider/pull/121)
- Fixed null refs in optional headers [#123](https://github.com/fsprojects/SwaggerProvider/pull/123)
#### 0.10.0-beta09 - November 5, 2019
- TP parameter names are unified [#129](https://github.com/fsprojects/SwaggerProvider/pull/129)
#### 0.10.0-beta08 - November 3, 2019
- Migration to new Type Provider SDK [#88](https://github.com/fsprojects/SwaggerProvider/pull/88) [#125](https://github.com/fsprojects/SwaggerProvider/pull/125)
- SwaggerParser moved to runtime assembly (and exposed as API to library users) - [#90](https://github.com/fsprojects/SwaggerProvider/pull/90)
- Added runtime dependency on YamlDotNet
- Removed dependency on FSharp.Data/JsonValue (replaced by JSON.NET)
- Added full-init constructor for provided types [#91](https://github.com/fsprojects/SwaggerProvider/pull/91)
-
gitextract_zkbrmfz_/
├── .config/
│ └── dotnet-tools.json
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── ISSUE_TEMPLATE.md
│ ├── aw/
│ │ └── actions-lock.json
│ ├── dependabot.yml
│ └── workflows/
│ ├── docs.yml
│ ├── dotnetcore.yml
│ ├── repo-assist.lock.yml
│ └── repo-assist.md
├── .gitignore
├── AGENTS.md
├── LICENSE.txt
├── README.md
├── SwaggerProvider.TestsAndDocs.sln
├── SwaggerProvider.sln
├── build.cmd
├── build.fsx
├── build.sh
├── docs/
│ ├── .gitignore
│ ├── .vitepress/
│ │ ├── config.mts
│ │ └── theme/
│ │ ├── custom.css
│ │ └── index.ts
│ ├── Customization.md
│ ├── OpenApiClientProvider.md
│ ├── RELEASE_NOTES.md
│ ├── files/
│ │ └── img/
│ │ └── logo.pdn
│ ├── getting-started.md
│ ├── index.md
│ └── package.json
├── global.json
├── paket.dependencies
├── src/
│ ├── Common/
│ │ └── AssemblyInfo.fs
│ ├── SwaggerProvider.DesignTime/
│ │ ├── Caching.fs
│ │ ├── DefinitionCompiler.fs
│ │ ├── OperationCompiler.fs
│ │ ├── Properties/
│ │ │ └── launchSettings.json
│ │ ├── Provider.OpenApiClient.fs
│ │ ├── SwaggerProvider.DesignTime.fsproj
│ │ ├── Utils.fs
│ │ └── paket.references
│ └── SwaggerProvider.Runtime/
│ ├── Exception.fs
│ ├── ProvidedApiClientBase.fs
│ ├── Runtime.fs
│ ├── RuntimeHelpers.fs
│ ├── SwaggerProvider.Runtime.fsproj
│ ├── SwaggerProvider.fsx
│ ├── paket.references
│ └── paket.template
└── tests/
├── SwaggerProvider.ProviderTests/
│ ├── APIs.Guru.FSC.Tests.fs
│ ├── Schemas/
│ │ ├── Instagram.json
│ │ ├── azure-arm-storage.json
│ │ ├── clickmeter.com.json
│ │ ├── github.json
│ │ ├── i0027.json
│ │ ├── issue132.json
│ │ ├── issue173.json
│ │ ├── issue181.yaml
│ │ ├── issue219.yaml
│ │ ├── issue255.yaml
│ │ ├── issue279.json
│ │ ├── my-swashbuckle.json
│ │ ├── nullable-date.yaml
│ │ ├── nullable-parameter-issue261.json
│ │ ├── petstore-v2.json
│ │ ├── petstore.yaml
│ │ ├── slack.json
│ │ ├── swashbuckle.json
│ │ └── unsupported/
│ │ ├── gettyimages.com.json
│ │ └── issue0204.yaml
│ ├── Script.fsx
│ ├── Swagger.I0173.Tests.fs
│ ├── Swagger.I0181.Tests.fs
│ ├── Swagger.I0219.Tests.fs
│ ├── Swagger.I0279.Tests.fs
│ ├── Swagger.NullableDate.Tests.fs
│ ├── Swagger.PetStore.Tests.fs
│ ├── Swagger.SchemaReaderErrors.Tests.fs
│ ├── SwaggerProvider.ProviderTests.fsproj
│ ├── Swashbuckle.CancellationToken.Tests.fs
│ ├── Swashbuckle.FileController.Tests.fs
│ ├── Swashbuckle.NoContentControllers.Tests.fs
│ ├── Swashbuckle.ResourceControllers.Tests.fs
│ ├── Swashbuckle.ReturnControllers.Tests.fs
│ ├── Swashbuckle.ReturnTextControllers.Tests.fs
│ ├── Swashbuckle.SpecialCasesControllers.Tests.fs
│ ├── Swashbuckle.UpdateControllers.Tests.fs
│ ├── paket.references
│ └── thing.fsx
├── SwaggerProvider.Tests/
│ ├── APIs.guru.fs
│ ├── PathResolutionTests.fs
│ ├── RuntimeHelpersTests.fs
│ ├── Schema.ArrayAndMapTypeMappingTests.fs
│ ├── Schema.DefinitionPathTests.fs
│ ├── Schema.OperationCompilationTests.fs
│ ├── Schema.Parser.Tests.fs
│ ├── Schema.TestHelpers.fs
│ ├── Schema.TypeMappingTests.fs
│ ├── Schema.V2SchemaCompilationTests.fs
│ ├── Schema.XmlDocTests.fs
│ ├── SsrfSecurityTests.fs
│ ├── SwaggerProvider.Tests.fsproj
│ ├── UtilsTests.fs
│ └── paket.references
├── Swashbuckle.WebApi.Server/
│ ├── Controllers/
│ │ ├── FileController.fs
│ │ ├── NoContentControllers.fs
│ │ ├── ResourceControllers.fs
│ │ ├── ReturnControllers.fs
│ │ ├── ReturnTextControllers.fs
│ │ ├── SpecialCasesControllers.fs
│ │ ├── Types.fs
│ │ ├── UpdateControllers.fs
│ │ └── ValuesController.fs
│ ├── Program.fs
│ ├── Properties/
│ │ └── launchSettings.json
│ ├── Startup.fs
│ ├── Swashbuckle.WebApi.Server.fsproj
│ ├── app.config
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ └── paket.references
└── test.fsx
Condensed preview — 122 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,896K chars).
[
{
"path": ".config/dotnet-tools.json",
"chars": 437,
"preview": "{\n \"version\": 1,\n \"isRoot\": true,\n \"tools\": {\n \"paket\": {\n \"version\": \"10.3.1\",\n \"commands\": [\n \""
},
{
"path": ".editorconfig",
"chars": 765,
"preview": "; EditorConfig helps developers define and maintain consistent\n; coding styles between different editors and IDEs.\n\n; Fo"
},
{
"path": ".gitattributes",
"chars": 639,
"preview": "# Auto detect text files\n* text=auto \n\n# Custom for Visual Studio\n*.cs diff=csharp text=auto eol=lf\n*.fs diff=csharp tex"
},
{
"path": ".github/ISSUE_TEMPLATE.md",
"chars": 730,
"preview": "### Description\n\nPlease provide a succinct description of your issue.\n\n### Repro steps\n\nPlease provide the steps require"
},
{
"path": ".github/aw/actions-lock.json",
"chars": 2576,
"preview": "{\n \"entries\": {\n \"actions/github-script@v9.0.0\": {\n \"repo\": \"actions/github-script\",\n \"version\": \"v9.0.0\","
},
{
"path": ".github/dependabot.yml",
"chars": 282,
"preview": "version: 2\nupdates:\n - package-ecosystem: \"github-actions\"\n directory: \"/\"\n schedule:\n interval: \"weekly\"\n "
},
{
"path": ".github/workflows/docs.yml",
"chars": 984,
"preview": "name: Deploy docs to GitHub Pages\n\non:\n push:\n branches: [master]\n paths:\n - 'docs/**'\n workflow_dispatch:\n"
},
{
"path": ".github/workflows/dotnetcore.yml",
"chars": 1246,
"preview": "name: Build and Test\n\non:\n push:\n branches:\n - master\n pull_request:\n\nconcurrency:\n group: ${{ github.workflo"
},
{
"path": ".github/workflows/repo-assist.lock.yml",
"chars": 112242,
"preview": "# gh-aw-metadata: {\"schema_version\":\"v3\",\"frontmatter_hash\":\"9795d605bdecebc79c8c5cbb8fbf7ffa7b3dfd48ab232f75dcff9e0b162"
},
{
"path": ".github/workflows/repo-assist.md",
"chars": 24192,
"preview": "---\ndescription: |\n A friendly repository assistant that runs 2 times a day to support contributors and maintainers.\n "
},
{
"path": ".gitignore",
"chars": 5762,
"preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## G"
},
{
"path": "AGENTS.md",
"chars": 3178,
"preview": "## Git Policy\n\n- **NEVER commit or push unless the user explicitly asks you to.** Only create commits when directly requ"
},
{
"path": "LICENSE.txt",
"chars": 1211,
"preview": "This is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, c"
},
{
"path": "README.md",
"chars": 2867,
"preview": "# SwaggerProvider\n\n[](https://www.nuget.org/packages/Swagger"
},
{
"path": "SwaggerProvider.TestsAndDocs.sln",
"chars": 4225,
"preview": "\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.2"
},
{
"path": "SwaggerProvider.sln",
"chars": 4305,
"preview": "\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.2"
},
{
"path": "build.cmd",
"chars": 75,
"preview": "@echo off\ndotnet tool restore\ndotnet paket restore\ndotnet fsi build.fsx %*\n"
},
{
"path": "build.fsx",
"chars": 7810,
"preview": "#r \"nuget: Fake.Core.Target\"\n#r \"nuget: Fake.Core.Process\"\n#r \"nuget: Fake.Core.ReleaseNotes\"\n#r \"nuget: Fake.IO.FileSys"
},
{
"path": "build.sh",
"chars": 144,
"preview": "#!/bin/bash\nif test \"$OS\" = \"Windows_NT\"\nthen\n cmd /C build.cmd\nelse\n dotnet tool restore\n dotnet paket restore\n dot"
},
{
"path": "docs/.gitignore",
"chars": 49,
"preview": "node_modules/\n.vitepress/cache/\n.vitepress/dist/\n"
},
{
"path": "docs/.vitepress/config.mts",
"chars": 1202,
"preview": "import { defineConfig } from \"vitepress\";\n\nexport default defineConfig({\n base: \"/SwaggerProvider/\",\n title: \"SwaggerP"
},
{
"path": "docs/.vitepress/theme/custom.css",
"chars": 357,
"preview": ":root {\n --vp-font-family-mono: \"Fira Code\", monospace;\n}\n\n.VPHero .image-container .image-bg {\n background-image: lin"
},
{
"path": "docs/.vitepress/theme/index.ts",
"chars": 94,
"preview": "import DefaultTheme from 'vitepress/theme'\nimport './custom.css'\n\nexport default DefaultTheme\n"
},
{
"path": "docs/Customization.md",
"chars": 5605,
"preview": "# Customization\n\nOpenAPI and Swagger type providers generate one or several API client types (depending on the value of "
},
{
"path": "docs/OpenApiClientProvider.md",
"chars": 5042,
"preview": "# OpenAPI Client Provider\n\nOpenApiClientProvider is a generative F# Type Provider, built on top of [Microsoft.OpenApi.Re"
},
{
"path": "docs/RELEASE_NOTES.md",
"chars": 17749,
"preview": "#### 4.0.0-beta02 - April 18, 2026\n\n- fix: preserve declared properties when schema has both `properties` and `additiona"
},
{
"path": "docs/getting-started.md",
"chars": 1683,
"preview": "# SwaggerProvider\n\n**SwaggerProvider** is an F# generative [Type Provider](https://learn.microsoft.com/en-us/dotnet/fsha"
},
{
"path": "docs/index.md",
"chars": 1405,
"preview": "---\nlayout: home\nhero:\n name: OpenAPI & Swagger F# Type Provider\n tagline: Strongly-typed HTTP clients from OpenAPI 3."
},
{
"path": "docs/package.json",
"chars": 206,
"preview": "{\n \"private\": true,\n \"scripts\": {\n \"docs:dev\": \"vitepress dev\",\n \"docs:build\": \"vitepress build\",\n \"docs:prev"
},
{
"path": "global.json",
"chars": 79,
"preview": "{\n \"sdk\": {\n \"version\": \"10.0.102\",\n \"rollForward\": \"latestMinor\"\n }\n}\n"
},
{
"path": "paket.dependencies",
"chars": 1308,
"preview": "version 9.0.2\nsource https://api.nuget.org/v3/index.json\nstorage: none\n\nnuget FSharp.Core ~> 8\nnuget System.Text.Json ~>"
},
{
"path": "src/Common/AssemblyInfo.fs",
"chars": 723,
"preview": "// Auto-Generated by FAKE; do not edit\nnamespace System\nopen System.Reflection\n\n[<assembly: AssemblyTitleAttribute(\"Swa"
},
{
"path": "src/SwaggerProvider.DesignTime/Caching.fs",
"chars": 4322,
"preview": "module SwaggerProvider.Caching\n\nopen System\nopen System.Collections.Concurrent\n\n// https://github.com/fsharp/FSharp.Data"
},
{
"path": "src/SwaggerProvider.DesignTime/DefinitionCompiler.fs",
"chars": 27649,
"preview": "namespace SwaggerProvider.Internal.Compilers\n\nopen System\nopen System.Reflection\nopen ProviderImplementation.ProvidedTyp"
},
{
"path": "src/SwaggerProvider.DesignTime/OperationCompiler.fs",
"chars": 30640,
"preview": "namespace SwaggerProvider.Internal.Compilers\n\nopen System\nopen System.Collections.Generic\nopen System.Net.Http\nopen Syst"
},
{
"path": "src/SwaggerProvider.DesignTime/Properties/launchSettings.json",
"chars": 383,
"preview": "{\n \"profiles\": {\n \"SwaggerProvider.DesignTime\": {\n \"commandName\": \"Project\"\n },\n \"DebugTP\": {\n \"comm"
},
{
"path": "src/SwaggerProvider.DesignTime/Provider.OpenApiClient.fs",
"chars": 8114,
"preview": "namespace SwaggerProvider\n\nopen System\nopen System.Reflection\nopen Microsoft.OpenApi.Reader\nopen ProviderImplementation."
},
{
"path": "src/SwaggerProvider.DesignTime/SwaggerProvider.DesignTime.fsproj",
"chars": 2612,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project Sdk=\"Microsoft.NET.Sdk\">\n <PropertyGroup>\n <OutputType>Library</Outp"
},
{
"path": "src/SwaggerProvider.DesignTime/Utils.fs",
"chars": 18296,
"preview": "namespace SwaggerProvider.Internal\n\nmodule SchemaReader =\n open System\n open System.IO\n open System.Net\n ope"
},
{
"path": "src/SwaggerProvider.DesignTime/paket.references",
"chars": 150,
"preview": "File: ProvidedTypes.fsi\nFile: ProvidedTypes.fs\nFile: Pluralizer.fs\nFile: NameUtils.fs\nSystem.Text.Json\nMicrosoft.OpenApi"
},
{
"path": "src/SwaggerProvider.Runtime/Exception.fs",
"chars": 506,
"preview": "[<AutoOpen>]\n[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]\nmodule System.Exception\n\nopen Sy"
},
{
"path": "src/SwaggerProvider.Runtime/ProvidedApiClientBase.fs",
"chars": 3348,
"preview": "namespace Swagger\n\nopen System\nopen System.Net.Http\nopen System.Threading.Tasks\nopen System.Text.Json\nopen System.Text.J"
},
{
"path": "src/SwaggerProvider.Runtime/Runtime.fs",
"chars": 204,
"preview": "namespace SwaggerProvider\n\n// TypeProviderAssemblyAttribute in the runtime DLL, pointing to the design-time DLL\n[<assemb"
},
{
"path": "src/SwaggerProvider.Runtime/RuntimeHelpers.fs",
"chars": 19104,
"preview": "namespace Swagger.Internal\n\nopen System\nopen System.Net.Http\nopen System.Net.Http.Headers\nopen System.Text.Json.Serializ"
},
{
"path": "src/SwaggerProvider.Runtime/SwaggerProvider.Runtime.fsproj",
"chars": 1870,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n <!-- See https://stackoverflow.com/questions/43921992/how-can-i-use-b"
},
{
"path": "src/SwaggerProvider.Runtime/SwaggerProvider.fsx",
"chars": 578,
"preview": "#nowarn \"211\"\n// Standard NuGet or Paket location\n#I \".\"\n#I \"lib/net461\"\n\n// Standard NuGet locations packages\n#I \"../Ne"
},
{
"path": "src/SwaggerProvider.Runtime/paket.references",
"chars": 82,
"preview": "File: ProvidedTypes.fsi\nFile: ProvidedTypes.fs\n\nFSharp.Core\nFSharp.SystemTextJson\n"
},
{
"path": "src/SwaggerProvider.Runtime/paket.template",
"chars": 1256,
"preview": "type file\nid SwaggerProvider\ntitle\n Swagger Provider\nowners\n Sergey Tihon\nauthors\n Sergey Tihon\nprojectUrl\n "
},
{
"path": "tests/SwaggerProvider.ProviderTests/APIs.Guru.FSC.Tests.fs",
"chars": 3668,
"preview": "module APIsGuruFSCS\n(*\nopen FSharp.Compiler.SourceCodeServices\nopen System\nopen System.IO\nopen Expecto\nopen Fake\n\nlet as"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/Instagram.json",
"chars": 51572,
"preview": "{\n \"swagger\": \"2.0\",\n \"info\": {\n \"version\": \"v1\",\n \"title\": \"Instagram API\",\n \"description\": "
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/azure-arm-storage.json",
"chars": 47042,
"preview": "{\n \"swagger\": \"2.0\",\n \"schemes\": [\n \"https\"\n ],\n \"host\": \"management.azure.com\",\n \"info\": {\n \"description\": \""
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/clickmeter.com.json",
"chars": 255374,
"preview": "{\n \"swagger\": \"2.0\",\n \"schemes\": [\n \"http\",\n \"https\"\n ],\n \"host\": \"apiv2.clickmeter.com:80\",\n \""
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/github.json",
"chars": 1780,
"preview": "{\n \"swagger\": \"2.0\",\n \"info\": {\n \"description\": \"This is a Sample for GitHub API.\",\n \"version\": \"1.0"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/i0027.json",
"chars": 11466,
"preview": "{\n \"swagger\": \"2.0\",\n \"info\": {\n \"version\": \"v1\",\n \"title\": \"Tenant API\"\n },\n \"host\": \"\",\n \"basePath\": \"5003\""
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/issue132.json",
"chars": 1595,
"preview": "{\n \"swagger\": \"2.0\",\n \"info\": {\n \"version\": \"v1\",\n \"title\": \" \",\n \"description\": \" \"\n },\n \"ho"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/issue173.json",
"chars": 561308,
"preview": "{\n \"openapi\": \"3.0.1\",\n \"info\": {\n \"title\": \"OdhApi Tourism .Net Core\",\n \"description\": \"ODH Tourism Api"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/issue181.yaml",
"chars": 1887,
"preview": "openapi: 3.0.0\ninfo:\n title: my-api-book\n version: '1.0'\nservers:\n - url: 'https://myapi.staging.acme.com'\n descri"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/issue219.yaml",
"chars": 35332,
"preview": "openapi: \"3.0.3\"\ninfo:\n title: \"Sample Api\"\n description: |\n # Some ACME API\n termsOfService: \"https://acmed3hdhhd"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/issue255.yaml",
"chars": 249,
"preview": "openapi: 3.0.0\npaths:\n /run:\n summary: Do nothing.\ncomponents:\n schemas:\n Person:\n title: Person\n allO"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/issue279.json",
"chars": 555106,
"preview": "{\n \"openapi\": \"3.0.0\",\n \"paths\": {\n \"/activities\": {\n \"get\": {\n \"description\": \"Returns a list of activ"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/my-swashbuckle.json",
"chars": 36978,
"preview": "{\n \"swagger\": \"2.0\",\n \"info\": { \"version\": \"v1\", \"title\": \"Test Controllers for SwaggerProvider\" },\n \"host\": \"localho"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/nullable-date.yaml",
"chars": 592,
"preview": "openapi: 3.0.0\ninfo:\n title: Nullable Date Test API\n version: 1.0.0\npaths:\n /test:\n get:\n operationId: getTes"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/nullable-parameter-issue261.json",
"chars": 756,
"preview": "{\n \"openapi\": \"3.0.0\",\n \"info\": {\n \"title\": \"Nullable Parameter Test\",\n \"version\": \"1.0.0\"\n },\n \"paths\": {\n "
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/petstore-v2.json",
"chars": 21060,
"preview": "{\n \"swagger\": \"2.0\",\n \"info\": {\n \"description\": \"This is a sample server Petstore server. You can find out more ab"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/petstore.yaml",
"chars": 20887,
"preview": "openapi: 3.0.2\ninfo:\n title: Swagger Petstore - OpenAPI 3.0\n description: \"This is a sample Pet Store Server based on "
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/slack.json",
"chars": 1117410,
"preview": "{\n \"basePath\": \"/api\",\n \"definitions\": {\n \"blocks\": {\n \"description\": \"This is a very loose defi"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/swashbuckle.json",
"chars": 20483,
"preview": "{\"swagger\":\"2.0\",\"info\":{\"version\":\"v1\",\"title\":\"Test Controllers for SwaggerProvider\"},\"host\":\"localhost:8735\",\"schemes"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/unsupported/gettyimages.com.json",
"chars": 319616,
"preview": "{\n \"swagger\": \"2.0\",\n \"schemes\": [\n \"https\"\n ],\n \"host\": \"api.gettyimages.com\",\n \"basePath\": \"/\",\n "
},
{
"path": "tests/SwaggerProvider.ProviderTests/Schemas/unsupported/issue0204.yaml",
"chars": 6553,
"preview": "openapi: 3.0.0\ninfo:\n description: This is our customer facing API for the Qorta platform\n version: v1\n title: Samba"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Script.fsx",
"chars": 2504,
"preview": "// Load SwaggerProvider\n#r @\"../../src/SwaggerProvider/bin/Release/SwaggerProvider.dll\"\nopen SwaggerProvider\n\n// Petstor"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Swagger.I0173.Tests.fs",
"chars": 210,
"preview": "module Swagger.I0173.Tests\n\nopen SwaggerProvider\n\n[<Literal>]\nlet Schema = __SOURCE_DIRECTORY__ + \"/Schemas/issue173.jso"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Swagger.I0181.Tests.fs",
"chars": 194,
"preview": "module Swagger.I0181.Tests\n\nopen SwaggerProvider\n\n[<Literal>]\nlet Schema = __SOURCE_DIRECTORY__ + \"/Schemas/issue181.yam"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Swagger.I0219.Tests.fs",
"chars": 198,
"preview": "module Swagger.I0219.Tests\n\nopen SwaggerProvider\n\n[<Literal>]\nlet Schema = __SOURCE_DIRECTORY__ + \"/Schemas/issue219.yam"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Swagger.I0279.Tests.fs",
"chars": 196,
"preview": "module Swagger.I0279.Tests\n\nopen SwaggerProvider\n\n[<Literal>]\nlet Schema = __SOURCE_DIRECTORY__ + \"/Schemas/issue279.jso"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Swagger.NullableDate.Tests.fs",
"chars": 3202,
"preview": "module Swagger.NullableDate.Tests\n\nopen SwaggerProvider\nopen Xunit\nopen FsUnitTyped\nopen System.Text.Json\nopen System.Te"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs",
"chars": 3474,
"preview": "module Swagger.PetStore.Tests\n\nopen SwaggerProvider\nopen Swagger\nopen FsUnitTyped\nopen Xunit\nopen System\nopen System.Net"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Swagger.SchemaReaderErrors.Tests.fs",
"chars": 975,
"preview": "module Swagger.SchemaReaderErrors.Tests\n\nopen SwaggerProvider\nopen Xunit\nopen FsUnitTyped\n\n[<Literal>]\nlet ValidSchema ="
},
{
"path": "tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj",
"chars": 1976,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project Sdk=\"Microsoft.NET.Sdk\">\n <PropertyGroup>\n <OutputType>Exe</OutputTy"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Swashbuckle.CancellationToken.Tests.fs",
"chars": 4304,
"preview": "module Swashbuckle.CancellationTokenTests\n\nopen Xunit\nopen FsUnitTyped\nopen System\nopen System.Net.Http\nopen System.Thre"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Swashbuckle.FileController.Tests.fs",
"chars": 1880,
"preview": "module Swashbuckle.FileControllersTests\n\nopen Xunit\nopen FsUnitTyped\nopen System.IO\nopen Swashbuckle.ReturnControllersTe"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Swashbuckle.NoContentControllers.Tests.fs",
"chars": 782,
"preview": "module Swashbuckle.NoContentControllersTests\n\nopen FsUnitTyped\nopen Xunit\nopen Swashbuckle.ReturnControllersTests\n\n[<Fac"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Swashbuckle.ResourceControllers.Tests.fs",
"chars": 1033,
"preview": "module Swashbuckle.ResourceControllersTests\n\nopen Xunit\nopen FsUnitTyped\nopen Swashbuckle.ReturnControllersTests\n\n[<Fac"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Swashbuckle.ReturnControllers.Tests.fs",
"chars": 4886,
"preview": "module Swashbuckle.ReturnControllersTests\n\nopen Xunit\nopen FsUnitTyped\nopen SwaggerProvider\nopen System\nopen System.Net."
},
{
"path": "tests/SwaggerProvider.ProviderTests/Swashbuckle.ReturnTextControllers.Tests.fs",
"chars": 842,
"preview": "module Swashbuckle.ReturnTextControllersTests\n\nopen Xunit\nopen FsUnitTyped\nopen SwaggerProvider\nopen System\nopen System."
},
{
"path": "tests/SwaggerProvider.ProviderTests/Swashbuckle.SpecialCasesControllers.Tests.fs",
"chars": 586,
"preview": "module Swashbuckle.SpecialCasesControllersTests\n\nopen Xunit\nopen Swashbuckle.ReturnControllersTests\n\n[<Fact>]\nlet ``Req"
},
{
"path": "tests/SwaggerProvider.ProviderTests/Swashbuckle.UpdateControllers.Tests.fs",
"chars": 5387,
"preview": "module Swashbuckle.UpdateControllersTests\n\nopen Xunit\nopen FsUnitTyped\nopen System\nopen Swashbuckle.ReturnControllersTes"
},
{
"path": "tests/SwaggerProvider.ProviderTests/paket.references",
"chars": 99,
"preview": "group Test\n FSharp.Compiler.Service\n FSharp.Core\n Microsoft.NET.Test.Sdk\n FsUnit.Xunit\n"
},
{
"path": "tests/SwaggerProvider.ProviderTests/thing.fsx",
"chars": 389,
"preview": "let createQuote(id: string) =\n printfn \"Creating Quote %A\" id\n\nlet closeQuote(id: string) =\n printfn \"Closing Quot"
},
{
"path": "tests/SwaggerProvider.Tests/APIs.guru.fs",
"chars": 1100,
"preview": "module APIsGuru\n\nopen System.Text.Json\nopen System.Net.Http\n\nlet httpClient = new HttpClient()\n\nlet private apisGuruList"
},
{
"path": "tests/SwaggerProvider.Tests/PathResolutionTests.fs",
"chars": 4826,
"preview": "namespace SwaggerProvider.Tests.PathResolutionTests\n\nopen System\nopen System.IO\nopen System.Runtime.InteropServices\nopen"
},
{
"path": "tests/SwaggerProvider.Tests/RuntimeHelpersTests.fs",
"chars": 42224,
"preview": "namespace SwaggerProvider.Tests.RuntimeHelpersTests\n\nopen System\nopen System.IO\nopen System.Net\nopen System.Net.Http\nope"
},
{
"path": "tests/SwaggerProvider.Tests/Schema.ArrayAndMapTypeMappingTests.fs",
"chars": 4877,
"preview": "module SwaggerProvider.Tests.Schema_ArrayAndMapTypeMappingTests\n\nopen System\nopen Xunit\nopen FsUnitTyped\n\n// ── Required"
},
{
"path": "tests/SwaggerProvider.Tests/Schema.DefinitionPathTests.fs",
"chars": 4414,
"preview": "module SwaggerProvider.Tests.Schema_DefinitionPathTests\n\n/// Unit tests for DefinitionPath.Parse — the function that spl"
},
{
"path": "tests/SwaggerProvider.Tests/Schema.OperationCompilationTests.fs",
"chars": 19003,
"preview": "module SwaggerProvider.Tests.Schema_OperationCompilationTests\n\n/// Unit tests for the v3 OperationCompiler — verifying g"
},
{
"path": "tests/SwaggerProvider.Tests/Schema.Parser.Tests.fs",
"chars": 4241,
"preview": "module SwaggerProvider.Tests.Schema_ParserTests\n\nopen Microsoft.OpenApi.Reader\nopen Xunit\nopen FsUnitTyped\nopen System\no"
},
{
"path": "tests/SwaggerProvider.Tests/Schema.TestHelpers.fs",
"chars": 4479,
"preview": "[<AutoOpen>]\nmodule SwaggerProvider.Tests.Schema_TestHelpers\n\nopen System\nopen Microsoft.OpenApi.Reader\nopen SwaggerProv"
},
{
"path": "tests/SwaggerProvider.Tests/Schema.TypeMappingTests.fs",
"chars": 16799,
"preview": "module SwaggerProvider.Tests.Schema_TypeMappingTests\n\nopen System\nopen Xunit\nopen FsUnitTyped\n\n// ── Required primitive "
},
{
"path": "tests/SwaggerProvider.Tests/Schema.V2SchemaCompilationTests.fs",
"chars": 8356,
"preview": "module SwaggerProvider.Tests.Schema_V2SchemaCompilationTests\n\n/// Tests that verify Swagger 2.0 schemas can be parsed an"
},
{
"path": "tests/SwaggerProvider.Tests/Schema.XmlDocTests.fs",
"chars": 6759,
"preview": "module SwaggerProvider.Tests.Schema_XmlDocTests\n\nopen System\nopen Microsoft.OpenApi.Reader\nopen SwaggerProvider.Internal"
},
{
"path": "tests/SwaggerProvider.Tests/SsrfSecurityTests.fs",
"chars": 14655,
"preview": "namespace SwaggerProvider.Tests.SsrfSecurityTests\n\nopen System\nopen Xunit\nopen SwaggerProvider.Internal.SchemaReader\n\n//"
},
{
"path": "tests/SwaggerProvider.Tests/SwaggerProvider.Tests.fsproj",
"chars": 1328,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project Sdk=\"Microsoft.NET.Sdk\">\n <PropertyGroup>\n <OutputType>Exe</OutputTy"
},
{
"path": "tests/SwaggerProvider.Tests/UtilsTests.fs",
"chars": 3692,
"preview": "namespace SwaggerProvider.Tests.UtilsTests\n\nopen Xunit\nopen FsUnitTyped\nopen SwaggerProvider.Internal\n\n/// Unit tests fo"
},
{
"path": "tests/SwaggerProvider.Tests/paket.references",
"chars": 140,
"preview": "group Test\n FSharp.Core\n FSharp.SystemTextJson\n FsUnit.xUnit\n Microsoft.NET.Test.Sdk\n Microsoft.OpenApi\n "
},
{
"path": "tests/Swashbuckle.WebApi.Server/Controllers/FileController.fs",
"chars": 2981,
"preview": "namespace Swashbuckle.WebApi.Server.Controllers\n\nopen System\nopen System.IO\nopen Microsoft.AspNetCore.Mvc\nopen Microsoft"
},
{
"path": "tests/Swashbuckle.WebApi.Server/Controllers/NoContentControllers.fs",
"chars": 1258,
"preview": "namespace Swashbuckle.WebApi.Server.Controllers\n\nopen Microsoft.AspNetCore.Mvc\n\n[<Route(\"api/[controller]\")>]\n[<ApiContr"
},
{
"path": "tests/Swashbuckle.WebApi.Server/Controllers/ResourceControllers.fs",
"chars": 928,
"preview": "namespace Swashbuckle.WebApi.Server.Controllers\n\nopen System.Collections.Generic\nopen Microsoft.AspNetCore.Mvc\nopen Swa"
},
{
"path": "tests/Swashbuckle.WebApi.Server/Controllers/ReturnControllers.fs",
"chars": 2195,
"preview": "namespace Swashbuckle.WebApi.Server.Controllers\n\nopen System\nopen Microsoft.AspNetCore.Mvc\nopen Swagger.Internal\n\n[<Rout"
},
{
"path": "tests/Swashbuckle.WebApi.Server/Controllers/ReturnTextControllers.fs",
"chars": 3170,
"preview": "namespace Swashbuckle.WebApi.Server.Controllers\n\nopen System.IO\nopen System.Text\nopen System.Threading.Tasks\nopen Micros"
},
{
"path": "tests/Swashbuckle.WebApi.Server/Controllers/SpecialCasesControllers.fs",
"chars": 587,
"preview": "namespace Swashbuckle.WebApi.Server.Controllers\n\nopen Microsoft.AspNetCore.Mvc\n\n[<Route(\"api/[controller]\")>]\n[<ApiContr"
},
{
"path": "tests/Swashbuckle.WebApi.Server/Controllers/Types.fs",
"chars": 472,
"preview": "module Types\n\nopen System.Runtime.Serialization\n\n[<DataContract>]\ntype PointClass(x: int, y: int) =\n new() = PointCl"
},
{
"path": "tests/Swashbuckle.WebApi.Server/Controllers/UpdateControllers.fs",
"chars": 2459,
"preview": "namespace Swashbuckle.WebApi.Server.Controllers\n\nopen System\nopen Microsoft.AspNetCore.Mvc\nopen System.Runtime.InteropS"
},
{
"path": "tests/Swashbuckle.WebApi.Server/Controllers/ValuesController.fs",
"chars": 654,
"preview": "namespace Swashbuckle.WebApi.Server.Controllers\n\n\n\n(*\n//[<Route(\"api/[controller]\")>]\n//[<ApiController>]\ntype ValuesCo"
},
{
"path": "tests/Swashbuckle.WebApi.Server/Program.fs",
"chars": 663,
"preview": "namespace Swashbuckle.WebApi.Server\n\nopen System\nopen Microsoft.AspNetCore\nopen Microsoft.AspNetCore.Hosting\n\nmodule Pro"
},
{
"path": "tests/Swashbuckle.WebApi.Server/Properties/launchSettings.json",
"chars": 755,
"preview": "{\n \"$schema\": \"http://json.schemastore.org/launchsettings.json\",\n \"iisSettings\": {\n \"windowsAuthentication\": false,"
},
{
"path": "tests/Swashbuckle.WebApi.Server/Startup.fs",
"chars": 2667,
"preview": "namespace Swashbuckle.WebApi.Server\n\n\nopen Microsoft.AspNetCore.Builder\nopen Microsoft.AspNetCore.Hosting\nopen Microsoft"
},
{
"path": "tests/Swashbuckle.WebApi.Server/Swashbuckle.WebApi.Server.fsproj",
"chars": 1297,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n <PropertyGroup>\n <TargetFramework>net1"
},
{
"path": "tests/Swashbuckle.WebApi.Server/app.config",
"chars": 129,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<configuration>\n <runtime>\n <gcServer enabled=\"true\"/>\n </runtime>\n</confi"
},
{
"path": "tests/Swashbuckle.WebApi.Server/appsettings.Development.json",
"chars": 137,
"preview": "{\n \"Logging\": {\n \"LogLevel\": {\n \"Default\": \"Debug\",\n \"System\": \"Information\",\n \"Microsoft\": \"Informat"
},
{
"path": "tests/Swashbuckle.WebApi.Server/appsettings.json",
"chars": 97,
"preview": "{\n \"Logging\": {\n \"LogLevel\": {\n \"Default\": \"Warning\"\n }\n },\n \"AllowedHosts\": \"*\"\n}\n"
},
{
"path": "tests/Swashbuckle.WebApi.Server/paket.references",
"chars": 190,
"preview": "group Server\n FSharp.Core\n Microsoft.AspNetCore\n Microsoft.AspNetCore.Mvc\n Microsoft.AspNetCore.HttpsPolicy\n"
},
{
"path": "tests/test.fsx",
"chars": 381,
"preview": "#I \"../src/SwaggerProvider.Runtime/bin/Release/netstandard2.0\"\n#I \"../src/SwaggerProvider.Runtime/bin/Release/typeprovid"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the fsprojects/SwaggerProvider GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 122 files (3.4 MB), approximately 903.7k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.