microsoft/semantic-kernel
21 workflows · maturity 83% · 7 patterns · GitHub ↗
Practices
✓ Matrix✓ Permissions✓ Security scan○ AI review✓ Cache✓ Concurrency○ Reusable workflows
Detected patterns
Security dimensions
Tools: github/codeql-action/analyze, github/codeql-action/autobuild, github/codeql-action/init
Workflows (21)
close-inactive-issues .github/workflows/close-inactive-issues.yml
View raw YAML
name: Close inactive issues
on:
schedule:
- cron: "30 1 * * *"
jobs:
close-issues:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v5
with:
days-before-issue-stale: 90
days-before-issue-close: 14
stale-issue-label: "stale"
stale-issue-message: "This issue is stale because it has been open for 90 days with no activity."
close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale."
days-before-pr-stale: -1
days-before-pr-close: -1
repo-token: ${{ secrets.GITHUB_TOKEN }}
codeql-analysis matrix security .github/workflows/codeql-analysis.yml
View raw YAML
# CodeQL is the code analysis engine developed by GitHub to automate security checks.
# The results are shown as code scanning alerts in GitHub. For more details, visit:
# https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/about-code-scanning-with-codeql
name: "CodeQL"
on:
workflow_dispatch:
push:
# TODO: Add "feature*" back in again, once we determine the cause of the ongoing CodeQL failures.
branches: ["main", "experimental*", "*-development"]
schedule:
- cron: "17 11 * * 2"
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: ["csharp", "python"]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Use only 'java' to analyze code written in Java, Kotlin or both
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
persist-credentials: false
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
if: ${{ matrix.language != 'java' }}
uses: github/codeql-action/autobuild@v3
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
devflow-pr-review perms .github/workflows/devflow-pr-review.yml
View raw YAML
name: DevFlow PR Review
on:
pull_request_target:
types:
- opened
- reopened
- ready_for_review
workflow_dispatch:
inputs:
pr_number:
description: Pull request number to review
required: true
type: string
permissions:
contents: read
issues: write
pull-requests: write
concurrency:
group: devflow-pr-review-${{ github.repository }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
env:
DEVFLOW_REPOSITORY: ${{ vars.DF_REPO }}
DEVFLOW_REF: main
TARGET_REPO_PATH: ${{ github.workspace }}/target-repo
DEVFLOW_PATH: ${{ github.workspace }}/devflow
jobs:
review:
runs-on: ubuntu-latest
timeout-minutes: 60
if: ${{ github.event_name != 'pull_request_target' || !github.event.pull_request.draft }}
steps:
- name: Resolve PR metadata
id: pr
shell: bash
env:
PR_HTML_URL: ${{ github.event.pull_request.html_url }}
PR_NUMBER_EVENT: ${{ github.event.pull_request.number }}
PR_NUMBER_INPUT: ${{ inputs.pr_number }}
run: |
set -euo pipefail
if [[ "${GITHUB_EVENT_NAME}" == "pull_request_target" ]]; then
pr_number="${PR_NUMBER_EVENT}"
pr_url="${PR_HTML_URL}"
else
pr_number="${PR_NUMBER_INPUT}"
pr_url="https://github.com/${GITHUB_REPOSITORY}/pull/${pr_number}"
fi
if [[ ! "$pr_number" =~ ^[1-9][0-9]*$ ]]; then
echo "Could not determine PR number; for workflow_dispatch runs, the 'pr_number' input is required when not running on pull_request_target." >&2
exit 1
fi
echo "pr_url=${pr_url}" >> "$GITHUB_OUTPUT"
echo "pr_number=${pr_number}" >> "$GITHUB_OUTPUT"
echo "repo=${GITHUB_REPOSITORY}" >> "$GITHUB_OUTPUT"
# Safe checkout: base repo only, not the untrusted PR head.
- name: Checkout target repo base
uses: actions/checkout@v5
with:
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.base.sha || github.sha }}
fetch-depth: 0
persist-credentials: false
path: target-repo
# Private DevFlow checkout: the PAT/token grants access to this repo's code.
- name: Checkout DevFlow
uses: actions/checkout@v5
with:
repository: ${{ env.DEVFLOW_REPOSITORY }}
ref: ${{ env.DEVFLOW_REF }}
token: ${{ secrets.DEVFLOW_TOKEN }}
fetch-depth: 1
persist-credentials: false
path: devflow
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
version: "0.5.x"
enable-cache: true
- name: Install DevFlow dependencies
working-directory: ${{ env.DEVFLOW_PATH }}
run: uv sync --frozen
- name: Classify PR relevance
id: spam
working-directory: ${{ env.DEVFLOW_PATH }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_COPILOT_TOKEN: ${{ secrets.GH_COPILOT_TOKEN }}
SK_REPO_PATH: ${{ env.TARGET_REPO_PATH }}
AGENT_REPO_PATH: ${{ env.TARGET_REPO_PATH }}
PR_REPO: ${{ steps.pr.outputs.repo }}
PR_NUMBER: ${{ steps.pr.outputs.pr_number }}
run: |
uv run python scripts/classify_pr_spam.py \
--repo "$PR_REPO" \
--pr-number "$PR_NUMBER" \
--repo-path "${TARGET_REPO_PATH}" \
--apply-labels
- name: Stop after spam gate
if: ${{ steps.spam.outputs.decision != 'allow' }}
shell: bash
env:
SPAM_DECISION: ${{ steps.spam.outputs.decision }}
run: |
echo "Skipping review because spam gate decided: ${SPAM_DECISION}"
- name: Run PR review
if: ${{ steps.spam.outputs.decision == 'allow' }}
id: review
working-directory: ${{ env.DEVFLOW_PATH }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_COPILOT_TOKEN: ${{ secrets.GH_COPILOT_TOKEN }}
SK_REPO_PATH: ${{ env.TARGET_REPO_PATH }}
AGENT_REPO_PATH: ${{ env.TARGET_REPO_PATH }}
PR_URL: ${{ steps.pr.outputs.pr_url }}
run: |
uv run python scripts/trigger_pr_review.py \
--pr-url "$PR_URL" \
--github-username "$GITHUB_ACTOR" \
--no-require-comment-selection
dotnet-build-and-test matrix perms .github/workflows/dotnet-build-and-test.yml
View raw YAML
#
# This workflow will build and run all unit tests using dotnet docker containers,
# each targeting a single version of the dotnet SDK.
#
name: dotnet-build-and-test
on:
workflow_dispatch:
pull_request:
branches: ["main", "feature*"]
merge_group:
branches: ["main"]
env:
COVERAGE_THRESHOLD: 80
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
id-token: "write"
jobs:
paths-filter:
runs-on: ubuntu-latest
outputs:
dotnetChanges: ${{ steps.filter.outputs.dotnet }}
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
dotnet:
- 'dotnet/**'
- '**/dotnet/**'
- '.github/workflows/check-coverage.ps1'
- '.github/workflows/dotnet-build-and-test.yml'
# run only if 'dotnet' files were changed
- name: dotnet tests
if: steps.filter.outputs.dotnet == 'true'
run: echo "Dotnet file"
# run only if not 'dotnet' files were changed
- name: not dotnet tests
if: steps.filter.outputs.dotnet != 'true'
run: echo "NOT dotnet file"
dotnet-build-and-test:
needs: paths-filter
if: needs.paths-filter.outputs.dotnetChanges == 'true'
strategy:
fail-fast: false
matrix:
include:
- {
dotnet: "10.0",
os: "ubuntu-latest",
configuration: Release,
integration-tests: true,
environment: "integration",
}
- { dotnet: "10.0", os: "windows-latest", configuration: Debug }
- { dotnet: "9.0", os: "windows-latest", configuration: Release }
runs-on: ${{ matrix.os }}
environment: ${{ matrix.environment }}
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
- name: Setup dotnet
uses: actions/setup-dotnet@v5
with:
global-json-file: ${{ github.workspace }}/dotnet/global.json
- name: Build dotnet solutions
shell: bash
run: |
export SOLUTIONS=$(find ./dotnet/ -type f -name "*.slnx" | tr '\n' ' ')
for solution in $SOLUTIONS; do
dotnet build $solution -c ${{ matrix.configuration }} --warnaserror
done
- name: Package install check
shell: bash
run: |
export SOLUTIONS=$(find ./dotnet/ -type f -name "*.slnx" | tr '\n' ' ')
for solution in $SOLUTIONS; do
dotnet pack $solution -c ${{ matrix.configuration }} --no-build --no-restore --output ./artifacts
done
dotnet new console --name packcheck --output consoleapp
# Create minimal nuget.config and use only dotnet nuget commands
echo '<?xml version="1.0" encoding="utf-8"?><configuration><packageSources><clear /></packageSources></configuration>' > consoleapp/nuget.config
# Add sources with local first using dotnet nuget commands
dotnet nuget add source ../artifacts --name local --configfile consoleapp/nuget.config
dotnet nuget add source https://api.nuget.org/v3/index.json --name nuget.org --configfile consoleapp/nuget.config
# Change to project directory to ensure local nuget.config is used
cd consoleapp
dotnet add packcheck.csproj package Microsoft.SemanticKernel
dotnet build -c ${{ matrix.configuration }} packcheck.csproj
cd ..
# Clean up
rm -rf ./artifacts
rm -rf ./consoleapp
- name: Run Unit Tests
shell: bash
run: |
export UT_PROJECTS=$(find ./dotnet -type f -name "*.UnitTests.csproj" | grep -v -E "(Experimental.Orchestration.Flow.UnitTests.csproj|Experimental.Assistants.UnitTests.csproj)" | tr '\n' ' ')
for project in $UT_PROJECTS; do
dotnet test -c ${{ matrix.configuration }} $project --no-build -v Normal --logger trx --collect:"XPlat Code Coverage" --results-directory:"TestResults/Coverage/" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.ExcludeByAttribute=GeneratedCodeAttribute,CompilerGeneratedAttribute,ExcludeFromCodeCoverageAttribute
done
- name: Run AOT Unit Tests
shell: pwsh
run: .github/workflows/test-aot-compatibility.ps1 ${{ matrix.dotnet }}
- name: Azure CLI Login
if: github.event_name != 'pull_request' && matrix.integration-tests
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Run Integration Tests
shell: bash
if: github.event_name != 'pull_request' && matrix.integration-tests
run: |
export INTEGRATION_TEST_PROJECTS=$(find ./dotnet -type f -name "*IntegrationTests.csproj" | grep -v "Experimental.Orchestration.Flow.IntegrationTests.csproj" | grep -v "VectorDataIntegrationTests.csproj" | tr '\n' ' ')
for project in $INTEGRATION_TEST_PROJECTS; do
dotnet test -f net10.0 -c ${{ matrix.configuration }} $project --no-build -v Normal --logger trx
done
env:
# Azure OpenAI Deployments
AzureOpenAI__Endpoint: ${{ secrets.AZUREOPENAI__ENDPOINT }}
AzureOpenAI__DeploymentName: ${{ vars.AZUREOPENAI__DEPLOYMENTNAME }}
AzureOpenAI__ChatDeploymentName: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }}
AzureOpenAIEmbeddings__Endpoint: ${{ secrets.AZUREOPENAI__ENDPOINT }}
AzureOpenAIEmbeddings__DeploymentName: ${{ vars.AZUREOPENAIEMBEDDING__DEPLOYMENTNAME }}
AzureOpenAITextToAudio__Endpoint: ${{ secrets.AZUREOPENAITEXTTOAUDIO__ENDPOINT }}
AzureOpenAITextToAudio__DeploymentName: ${{ vars.AZUREOPENAITEXTTOAUDIO__DEPLOYMENTNAME }}
AzureOpenAIAudioToText__Endpoint: ${{ secrets.AZUREOPENAIAUDIOTOTEXT__ENDPOINT }}
AzureOpenAIAudioToText__DeploymentName: ${{ vars.AZUREOPENAIAUDIOTOTEXT__DEPLOYMENTNAME }}
AzureOpenAITextToImage__Endpoint: ${{ secrets.AZUREOPENAITEXTTOIMAGE__ENDPOINT }}
AzureOpenAITextToImage__DeploymentName: ${{ vars.AZUREOPENAITEXTTOIMAGE__DEPLOYMENTNAME }}
Planners__AzureOpenAI__Endpoint: ${{ secrets.PLANNERS__AZUREOPENAI__ENDPOINT }}
Planners__AzureOpenAI__DeploymentName: ${{ vars.PLANNERS__AZUREOPENAI__DEPLOYMENTNAME }}
# OpenAI Models
OpenAI__ApiKey: ${{ secrets.OPENAI__APIKEY }}
OpenAI__ChatModelId: ${{ vars.OPENAI__CHATMODELID }}
OpenAIEmbeddings__ApiKey: ${{ secrets.OPENAIEMBEDDINGS__APIKEY }}
OpenAIEmbeddings__ModelId: ${{ vars.OPENAIEMBEDDINGS__MODELID }}
OpenAITextToAudio__ApiKey: ${{ secrets.OPENAITEXTTOAUDIO__APIKEY }}
OpenAITextToAudio__ModelId: ${{ vars.OPENAITEXTTOAUDIO__MODELID }}
OpenAIAudioToText__ApiKey: ${{ secrets.OPENAIAUDIOTOTEXT__APIKEY }}
OpenAIAudioToText__ModelId: ${{ vars.OPENAIAUDIOTOTEXT__MODELID }}
OpenAITextToImage__ApiKey: ${{ secrets.OPENAITEXTTOIMAGE__APIKEY }}
OpenAITextToImage__ModelId: ${{ vars.OPENAITEXTTOIMAGE__MODELID }}
Planners__OpenAI__ApiKey: ${{ secrets.PLANNERS__OPENAI__APIKEY }}
Planners__OpenAI__ModelId: ${{ vars.PLANNERS__OPENAI__MODELID }}
# Bing Web Search
Bing__ApiKey: ${{ secrets.BING__APIKEY }}
# Google Web Search
Google__SearchEngineId: ${{ secrets.GOOGLE__SEARCHENGINEID }}
Google__ApiKey: ${{ secrets.GOOGLE__APIKEY }}
# Azure AI Inference Endpoint
AzureAIInference__ApiKey: ${{ secrets.AZUREAIINFERENCE__APIKEY }}
AzureAIInference__Endpoint: ${{ secrets.AZUREAIINFERENCE__ENDPOINT }}
AzureAIInference__ChatModelId: ${{ vars.AZUREAIINFERENCE__CHATMODELID }}
# Azure AI Foundry
AzureAI__Endpoint: ${{ secrets.AZUREAI__ENDPOINT }}
AzureAI__ConnectionString: ${{ secrets.AZUREAI__CONNECTIONSTRING }}
AzureAI__ChatModelId: ${{ vars.AZUREAI__CHATMODELID }}
# Generate test reports and check coverage
- name: Generate test reports
uses: danielpalme/ReportGenerator-GitHub-Action@5.4.12
with:
reports: "./TestResults/Coverage/**/coverage.cobertura.xml"
targetdir: "./TestResults/Reports"
reporttypes: "HtmlInline;JsonSummary"
- name: Upload coverage report artifact
uses: actions/upload-artifact@v4
with:
name: CoverageReport-${{ matrix.os }}-${{ matrix.dotnet }}-${{ matrix.configuration }} # Artifact name
path: ./TestResults/Reports # Directory containing files to upload
- name: Check coverage
shell: pwsh
run: .github/workflows/check-coverage.ps1 -JsonReportPath "TestResults/Reports/Summary.json" -CoverageThreshold $env:COVERAGE_THRESHOLD
# This final job is required to satisfy the merge queue. It must only run (or succeed) if no tests failed
dotnet-build-and-test-check:
if: always()
runs-on: ubuntu-latest
needs: [dotnet-build-and-test]
steps:
- name: Get Date
shell: bash
run: |
echo "date=$(date +'%m/%d/%Y %H:%M:%S')" >> "$GITHUB_ENV"
- name: Run Type is Daily
if: ${{ github.event_name == 'schedule' }}
shell: bash
run: |
echo "run_type=Daily" >> "$GITHUB_ENV"
- name: Run Type is Manual
if: ${{ github.event_name == 'workflow_dispatch' }}
shell: bash
run: |
echo "run_type=Manual" >> "$GITHUB_ENV"
- name: Run Type is ${{ github.event_name }}
if: ${{ github.event_name != 'schedule' && github.event_name != 'workflow_dispatch'}}
shell: bash
run: |
echo "run_type=${{ github.event_name }}" >> "$GITHUB_ENV"
- name: Fail workflow if tests failed
id: check_tests_failed
if: contains(join(needs.*.result, ','), 'failure')
uses: actions/github-script@v6
with:
script: core.setFailed('Integration Tests Failed!')
- name: Fail workflow if tests cancelled
id: check_tests_cancelled
if: contains(join(needs.*.result, ','), 'cancelled')
uses: actions/github-script@v6
with:
script: core.setFailed('Integration Tests Cancelled!')
dotnet-ci matrix perms .github/workflows/dotnet-ci.yml
View raw YAML
#
# This workflow will build and run all tests using dotnet docker containers,
# each targeting a single version of the dotnet SDK.
#
name: dotnet-ci
on:
workflow_dispatch:
schedule:
- cron: '0 7 * * *'
permissions:
contents: read
jobs:
build-and-test-docker:
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-latest, dotnet: '10.0', configuration: Debug }
- { os: ubuntu-latest, dotnet: '10.0', configuration: Release }
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
with:
clean: true
persist-credentials: false
- name: Find solutions
shell: bash
run: echo "solutions=$(find ./ -type f -name "*.slnx" | tr '\n' ' ')" >> $GITHUB_ENV
- name: Pull container dotnet/sdk:${{ matrix.dotnet }}
run: |
docker pull mcr.microsoft.com/dotnet/sdk:${{ matrix.dotnet }}
- name: Build
run: |
for solution in ${{ env.solutions }}; do
docker run --rm -v $(pwd):/app -w /app -e GITHUB_ACTIONS='true' mcr.microsoft.com/dotnet/sdk:${{ matrix.dotnet }} /bin/sh -c "dotnet build -c ${{ matrix.configuration }} /app/$solution"
done
- name: Find test projects
shell: bash
run: echo "testprojects=$(find ./dotnet -type f -name "*UnitTests.csproj" | tr '\n' ' ')" >> $GITHUB_ENV
- name: Run Tests
shell: bash
run: |
for project in ${{ env.testprojects }}; do
docker run --rm -v $(pwd):/app -w /app mcr.microsoft.com/dotnet/sdk:${{ matrix.dotnet }} /bin/sh -c "dotnet test -c ${{ matrix.configuration }} /app/$project --no-build -v Normal --logger trx"
done
- name: Upload dotnet test results
uses: actions/upload-artifact@v4
with:
name: dotnet-testresults-${{ matrix.configuration }}
path: ./TestResults
if: ${{ always() }}
build-and-test-windows:
strategy:
fail-fast: false
matrix:
os: [windows-latest]
configuration: [Release, Debug]
dotnet-version: ['10.0.x']
runs-on: ${{ matrix.os }}
env:
NUGET_CERT_REVOCATION_MODE: offline
steps:
- uses: actions/checkout@v5
with:
clean: true
persist-credentials: false
- name: Setup .NET SDK ${{ matrix.dotnet-version }}
uses: actions/setup-dotnet@v5
with:
dotnet-version: ${{ matrix.dotnet-version }}
env:
NUGET_AUTH_TOKEN: ${{ secrets.GPR_READ_TOKEN }}
- uses: actions/cache@v4
with:
path: ~/.nuget/packages
# Look to see if there is a cache hit for the corresponding requirements file
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
restore-keys: |
${{ runner.os }}-nuget
- name: Find solutions
shell: bash
run: echo "solutions=$(find ./dotnet -type f -name "*.slnx" | tr '\n' ' ')" >> $GITHUB_ENV
- name: Restore dependencies
shell: bash
run: |
for solution in ${{ env.solutions }}; do
dotnet restore $solution
done
- name: Build
shell: bash
run: |
for solution in ${{ env.solutions }}; do
dotnet build $solution --no-restore --configuration ${{ matrix.configuration }}
done
- name: Find test projects
shell: bash
run: echo "testprojects=$(find ./dotnet -type f -name "*Tests.csproj" | tr '\n' ' ')" >> $GITHUB_ENV
- name: Run Tests
shell: bash
run: |
for project in ${{ env.testprojects }}; do
dotnet test $project --verbosity normal --logger trx --results-directory ./TestResults --configuration ${{ matrix.configuration }}
done
- name: Upload dotnet test results
uses: actions/upload-artifact@v4
with:
name: dotnet-testresults-${{ matrix.configuration }}
path: ./TestResults
if: ${{ always() }}
dotnet-format matrix .github/workflows/dotnet-format.yml
View raw YAML
#
# This workflow runs the dotnet formatter on all c-sharp code.
#
name: dotnet-format
on:
workflow_dispatch:
pull_request:
branches: ["main", "feature*"]
paths:
- "dotnet/**"
- "samples/dotnet/**"
- "**.cs"
- "**.csproj"
- "**.editorconfig"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
check-format:
strategy:
fail-fast: false
matrix:
include:
- { dotnet: "10.0", configuration: Release, os: ubuntu-latest }
runs-on: ${{ matrix.os }}
env:
NUGET_CERT_REVOCATION_MODE: offline
steps:
- name: Check out code
uses: actions/checkout@v5
with:
fetch-depth: 0
persist-credentials: false
- name: Get changed files
id: changed-files
if: github.event_name == 'pull_request'
uses: jitterbit/get-changed-files@v1
continue-on-error: true
- name: No C# files changed
id: no-csharp
if: github.event_name == 'pull_request' && steps.changed-files.outputs.added_modified == ''
run: echo "No C# files changed"
# This step will loop over the changed files and find the nearest .csproj file for each one, then store the unique csproj files in a variable
- name: Find csproj files
id: find-csproj
if: github.event_name != 'pull_request' || steps.changed-files.outputs.added_modified != '' || steps.changed-files.outcome == 'failure'
run: |
csproj_files=()
exclude_files=("Experimental.Orchestration.Flow.csproj" "Experimental.Orchestration.Flow.UnitTests.csproj" "Experimental.Orchestration.Flow.IntegrationTests.csproj")
if [[ ${{ steps.changed-files.outcome }} == 'success' ]]; then
for file in ${{ steps.changed-files.outputs.added_modified }}; do
echo "$file was changed"
dir="./$file"
while [[ $dir != "." && $dir != "/" && $dir != $GITHUB_WORKSPACE ]]; do
if find "$dir" -maxdepth 1 -name "*.csproj" -print -quit | grep -q .; then
csproj_path="$(find "$dir" -maxdepth 1 -name "*.csproj" -print -quit)"
if [[ ! "${exclude_files[@]}" =~ "${csproj_path##*/}" ]]; then
csproj_files+=("$csproj_path")
fi
break
fi
dir=$(echo ${dir%/*})
done
done
else
# if the changed-files step failed, run dotnet on the whole slnx instead of specific projects
csproj_files=$(find ./ -type f -name "*.slnx" | tr '\n' ' ');
fi
csproj_files=($(printf "%s\n" "${csproj_files[@]}" | sort -u))
echo "Found ${#csproj_files[@]} unique csproj/slnx files: ${csproj_files[*]}"
echo "::set-output name=csproj_files::${csproj_files[*]}"
- name: Pull container dotnet/sdk:${{ matrix.dotnet }}
if: steps.find-csproj.outputs.csproj_files != ''
run: docker pull mcr.microsoft.com/dotnet/sdk:${{ matrix.dotnet }}
# This step will run dotnet format on each of the unique csproj files and fail if any changes are made
- name: Run dotnet format
if: steps.find-csproj.outputs.csproj_files != ''
run: |
for csproj in ${{ steps.find-csproj.outputs.csproj_files }}; do
echo "Running dotnet format on $csproj"
docker run --rm -v $(pwd):/app -w /app mcr.microsoft.com/dotnet/sdk:${{ matrix.dotnet }} /bin/sh -c "dotnet format $csproj --verify-no-changes --verbosity diagnostic"
done
dotnet-integration-tests matrix perms .github/workflows/dotnet-integration-tests.yml
View raw YAML
#
# This workflow will run all dotnet integrations tests.
#
name: dotnet-integration-tests
on:
workflow_dispatch:
pull_request:
branches: ["main"]
merge_group:
branches: ["main"]
permissions:
contents: read
jobs:
integration-tests:
strategy:
matrix:
os: [ubuntu-latest]
configuration: [Debug]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
if: ${{ github.event_name != 'pull_request' }}
with:
clean: true
persist-credentials: false
- name: Setup .NET
uses: actions/setup-dotnet@v5
if: ${{ github.event_name != 'pull_request' }}
with:
dotnet-version: 10.0.x
- name: Find projects
shell: bash
if: ${{ github.event_name != 'pull_request' }}
run: echo "projects=$(find ./dotnet -type f -name "*Tests.csproj" | tr '\n' ' ')" >> $GITHUB_ENV
- name: Integration Tests
shell: bash
if: ${{ github.event_name != 'pull_request' }}
env: # Set Azure credentials secret as an input
AzureOpenAI__Label: azure-text-davinci-003
AzureOpenAIEmbedding__Label: azure-text-embedding-ada-002
AzureOpenAI__DeploymentName: ${{ vars.AZUREOPENAI__DEPLOYMENTNAME }}
AzureOpenAIEmbeddings__DeploymentName: ${{ vars.AZUREOPENAIEMBEDDING__DEPLOYMENTNAME }}
AzureOpenAI__Endpoint: ${{ secrets.AZUREOPENAI__ENDPOINT }}
AzureOpenAIEmbeddings__Endpoint: ${{ secrets.AZUREOPENAI__ENDPOINT }}
AzureOpenAI__ApiKey: ${{ secrets.AZUREOPENAI__APIKEY }}
AzureOpenAIEmbeddings__ApiKey: ${{ secrets.AZUREOPENAI__APIKEY }}
AzureAI__ConnectionString: ${{ secrets.AZUREAI__CONNECTIONSTRING }}
Bing__ApiKey: ${{ secrets.BING__APIKEY }}
OpenAI__ApiKey: ${{ secrets.OPENAI__APIKEY }}
run: |
for project in ${{ env.projects }}; do
dotnet test $project --verbosity normal --logger trx --results-directory ./TestResults --configuration ${{ matrix.configuration }}
done
- name: Upload dotnet test results
uses: actions/upload-artifact@v4
with:
name: dotnet-testresults-${{ matrix.configuration }}
path: ./TestResults
if: ${{ github.event_name != 'pull_request' && always() }}
label-discussions .github/workflows/label-discussions.yml
View raw YAML
name: Label Discussions
on:
discussion:
types:
- created
jobs:
label_discussions:
runs-on: ubuntu-latest
permissions:
discussions: write
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Always add "triage" label
if: >
github.event.discussion.node_id != '' &&
(github.event.discussion.category.name == 'General' ||
github.event.discussion.category.name == 'Ideas' ||
github.event.discussion.category.name == 'Q&A')
uses: octokit/graphql-action@v2.x
with:
query: |
mutation($labelableId: ID!) {
addLabelsToLabelable(
input: {
labelableId: $labelableId
labelIds: ["LA_kwDOJDJ_Yc8AAAABU2klmQ"]
}
) {
clientMutationId
}
}
variables: |
{
"labelableId": "${{ github.event.discussion.node_id }}"
}
- name: Conditionally add "python" label
if: >
github.event.discussion.node_id != '' &&
(github.event.discussion.category.name == 'General' ||
github.event.discussion.category.name == 'Ideas' ||
github.event.discussion.category.name == 'Q&A') &&
(contains(github.event.discussion.body, 'python') ||
contains(github.event.discussion.body, 'Python') ||
contains(github.event.discussion.title, 'python') ||
contains(github.event.discussion.title, 'Python'))
uses: octokit/graphql-action@v2.x
with:
query: |
mutation($labelableId: ID!) {
addLabelsToLabelable(
input: {
labelableId: $labelableId
labelIds: ["LA_kwDOJDJ_Yc8AAAABO0f2Lg"]
}
) {
clientMutationId
}
}
variables: |
{
"labelableId": "${{ github.event.discussion.node_id }}"
}
- name: Conditionally add ".NET" label
if: >
github.event.discussion.node_id != '' &&
(github.event.discussion.category.name == 'General' ||
github.event.discussion.category.name == 'Ideas' ||
github.event.discussion.category.name == 'Q&A') &&
(contains(github.event.discussion.body, '.net') ||
contains(github.event.discussion.body, '.NET') ||
contains(github.event.discussion.title, '.net') ||
contains(github.event.discussion.title, '.NET') ||
contains(github.event.discussion.body, 'dotnet') ||
contains(github.event.discussion.body, 'DotNet') ||
contains(github.event.discussion.title, 'dotnet') ||
contains(github.event.discussion.title, 'DotNet') ||
contains(github.event.discussion.body, 'c#') ||
contains(github.event.discussion.body, 'C#') ||
contains(github.event.discussion.title, 'c#') ||
contains(github.event.discussion.title, 'C#') ||
contains(github.event.discussion.body, 'csharp') ||
contains(github.event.discussion.body, 'CSharp') ||
contains(github.event.discussion.title, 'csharp') ||
contains(github.event.discussion.title, 'CSharp'))
uses: octokit/graphql-action@v2.x
with:
query: |
mutation($labelableId: ID!) {
addLabelsToLabelable(
input: {
labelableId: $labelableId
labelIds: ["LA_kwDOJDJ_Yc8AAAABN_r7Lw"]
}
) {
clientMutationId
}
}
variables: |
{
"labelableId": "${{ github.event.discussion.node_id }}"
}
label-issues .github/workflows/label-issues.yml
View raw YAML
name: Label issues
on:
issues:
types:
- reopened
- opened
jobs:
label_issues:
name: "Issue: add labels"
if: ${{ github.event.action == 'opened' || github.event.action == 'reopened' }}
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- uses: actions/github-script@v6
with:
github-token: ${{ secrets.GH_ACTIONS_PR_WRITE }}
script: |
// Get the issue body and title
const body = context.payload.issue.body
let title = context.payload.issue.title
// Define the labels array
let labels = ["triage"]
// Check if the body or the title contains the word 'python' (case-insensitive)
if ((body != null && body.match(/python/i)) || (title != null && title.match(/python/i))) {
// Add the 'python' label to the array
labels.push("python")
}
// Check if the body or the title contains the word 'java' (case-insensitive)
if ((body != null && body.match(/java/i)) || (title != null && title.match(/java/i))) {
// Add the 'java' label to the array
labels.push("java")
}
// Check if the body or the title contains the words 'dotnet', '.net', 'c#' or 'csharp' (case-insensitive)
if ((body != null && body.match(/.net/i)) || (title != null && title.match(/.net/i)) ||
(body != null && body.match(/dotnet/i)) || (title != null && title.match(/dotnet/i)) ||
(body != null && body.match(/C#/i)) || (title != null && title.match(/C#/i)) ||
(body != null && body.match(/csharp/i)) || (title != null && title.match(/csharp/i))) {
// Add the '.NET' label to the array
labels.push(".NET")
}
// Add the labels to the issue
github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: labels
});
label-pr .github/workflows/label-pr.yml
View raw YAML
# This workflow will triage pull requests and apply a label based on the
# paths that are modified in the pull request.
#
# To use this workflow, you will need to set up a .github/labeler.yml
# file with configuration. For more information, see:
# https://github.com/actions/labeler
name: Label pull request
on: [pull_request_target]
jobs:
add_label:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/labeler@v4
with:
repo-token: "${{ secrets.GH_ACTIONS_PR_WRITE }}"
label-title-prefix .github/workflows/label-title-prefix.yml
View raw YAML
name: Label title prefix
on:
issues:
types: [labeled]
pull_request_target:
types: [labeled]
jobs:
add_title_prefix:
name: "Issue/PR: add title prefix"
continue-on-error: true
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/github-script@v6
name: "Issue/PR: update title"
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
let prefixLabels = {
"python": "Python",
"java": "Java",
".NET": ".Net"
};
function addTitlePrefix(title, prefix)
{
// Update the title based on the label and prefix
// Check if the title starts with the prefix (case-sensitive)
if (!title.startsWith(prefix + ": ")) {
// If not, check if the first word is the label (case-insensitive)
if (title.match(new RegExp(`^${prefix}`, 'i'))) {
// If yes, replace it with the prefix (case-sensitive)
title = title.replace(new RegExp(`^${prefix}`, 'i'), prefix);
} else {
// If not, prepend the prefix to the title
title = prefix + ": " + title;
}
}
return title;
}
labelAdded = context.payload.label.name
// Check if the issue or PR has the label
if (labelAdded in prefixLabels) {
let prefix = prefixLabels[labelAdded];
switch(context.eventName) {
case 'issues':
github.rest.issues.update({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
title: addTitlePrefix(context.payload.issue.title, prefix)
});
break
case 'pull_request_target':
github.rest.pulls.update({
pull_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
title: addTitlePrefix(context.payload.pull_request.title, prefix)
});
break
default:
core.setFailed('Unrecognited eventName: ' + context.eventName);
}
}
markdown-link-check perms .github/workflows/markdown-link-check.yml
View raw YAML
name: Check .md links
on:
workflow_dispatch:
pull_request:
branches: ["main"]
permissions:
contents: read
jobs:
markdown-link-check:
runs-on: ubuntu-22.04
# check out the latest version of the code
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
# Checks the status of hyperlinks in all files
- name: Run linkspector
uses: umbrelladocs/action-linkspector@v1
with:
reporter: local
filter_mode: nofilter
fail_on_error: true
config_file: ".github/.linkspector.yml"
merge-gatekeeper .github/workflows/merge-gatekeeper.yml
View raw YAML
name: Merge Gatekeeper
on:
pull_request:
branches: [ "main", "feature*" ]
merge_group:
branches: ["main"]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
merge-gatekeeper:
runs-on: ubuntu-latest
# Restrict permissions of the GITHUB_TOKEN.
# Docs: https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
permissions:
checks: read
statuses: read
steps:
- name: Run Merge Gatekeeper
# NOTE: v1 is updated to reflect the latest v1.x.y. Please use any tag/branch that suits your needs:
# https://github.com/upsidr/merge-gatekeeper/tags
# https://github.com/upsidr/merge-gatekeeper/branches
uses: upsidr/merge-gatekeeper@v1
if: github.event_name == 'pull_request'
with:
token: ${{ secrets.GITHUB_TOKEN }}
timeout: 3600
interval: 30
ignored: python-tests-coverage
python-build perms .github/workflows/python-build.yml
View raw YAML
name: Python Build Assets
on:
release:
types: [published]
permissions:
contents: write
id-token: write
jobs:
python-build-assets:
if: github.event_name == 'release' && startsWith(github.event.release.tag_name, 'python-')
name: Python Build Assets and add to Release
runs-on: ubuntu-latest
environment: "integration"
env:
UV_PYTHON: "3.10"
steps:
- uses: actions/checkout@v5
- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
version: "0.5.x"
enable-cache: true
cache-suffix: ${{ runner.os }}-${{ matrix.python-version }}
cache-dependency-glob: "**/uv.lock"
- name: Check version
run: |
echo "Building and uploading Python package version: ${{ github.event.release.tag_name }}"
- name: Build the package
run: cd python && make build
- name: Release
uses: softprops/action-gh-release@v2
with:
files: |
python/dist/*
- name: Azure Login
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Start DevOps pipeline
uses: azure/cli@v2
with:
inlineScript: |
az pipelines run --id ${{ vars.ADO_PYTHON_RELEASE_ID }} --org ${{ vars.ADO_ORG }} --project ${{ vars.ADO_PROJECT_NAME }} --parameters tag=${{ github.event.release.tag_name }} delay=0
python-integration-tests matrix perms .github/workflows/python-integration-tests.yml
View raw YAML
#
# This workflow will run all python integrations tests.
#
name: Python Integration Tests
on:
workflow_dispatch:
pull_request:
branches: ["main"]
merge_group:
branches: ["main"]
schedule:
- cron: "0 0 * * *" # Run at midnight UTC daily
permissions:
contents: read
id-token: "write"
env:
# Configure a constant location for the uv cache
UV_CACHE_DIR: /tmp/.uv-cache
Python_Integration_Tests: Python_Integration_Tests
INTEGRATION_TEST_SERVICE_SETUP_EXCEPTION: ${{ true }}
AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME }} # azure-text-embedding-ada-002
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_CHAT_DEPLOYMENT_NAME }}
AZURE_OPENAI_TEXT_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_TEXT_DEPLOYMENT_NAME }}
AZURE_OPENAI_AUDIO_TO_TEXT_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_AUDIO_TO_TEXT_DEPLOYMENT_NAME }}
AZURE_OPENAI_TEXT_TO_AUDIO_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_TEXT_TO_AUDIO_DEPLOYMENT_NAME }}
AZURE_OPENAI_TEXT_TO_IMAGE_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_TEXT_TO_IMAGE_DEPLOYMENT_NAME }}
AZURE_OPENAI_API_VERSION: ${{ vars.AZURE_OPENAI_API_VERSION }}
AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }}
AZURE_OPENAI_AUDIO_TO_TEXT_ENDPOINT: ${{ secrets.AZURE_OPENAI_AUDIO_TO_TEXT_ENDPOINT }}
AZURE_OPENAI_TEXT_TO_AUDIO_ENDPOINT: ${{ secrets.AZURE_OPENAI_TEXT_TO_AUDIO_ENDPOINT }}
AZURE_AI_AGENT_ENDPOINT: ${{ secrets.AZURE_AI_AGENT_ENDPOINT }}
AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME: ${{ secrets.AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME }}
AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME }}
BING_API_KEY: ${{ secrets.BING_API_KEY }}
OPENAI_RESPONSES_MODEL_ID: ${{ vars.OPENAI_RESPONSES_MODEL_ID }}
OPENAI_CHAT_MODEL_ID: ${{ vars.OPENAI_CHAT_MODEL_ID }}
OPENAI_TEXT_MODEL_ID: ${{ vars.OPENAI_TEXT_MODEL_ID }}
OPENAI_EMBEDDING_MODEL_ID: ${{ vars.OPENAI_EMBEDDING_MODEL_ID }}
OPENAI_AUDIO_TO_TEXT_MODEL_ID: ${{ vars.OPENAI_AUDIO_TO_TEXT_MODEL_ID }}
OPENAI_TEXT_TO_AUDIO_MODEL_ID: ${{ vars.OPENAI_TEXT_TO_AUDIO_MODEL_ID }}
OPENAI_TEXT_TO_IMAGE_MODEL_ID: ${{ vars.OPENAI_TEXT_TO_IMAGE_MODEL_ID }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
PINECONE_API_KEY: ${{ secrets.PINECONE__APIKEY }}
POSTGRES_CONNECTION_STRING: ${{secrets.POSTGRES__CONNECTIONSTR}}
POSTGRES_MAX_POOL: ${{ vars.POSTGRES_MAX_POOL }}
AZURE_AI_SEARCH_API_KEY: ${{secrets.AZURE_AI_SEARCH_API_KEY}}
AZURE_AI_SEARCH_ENDPOINT: ${{secrets.AZURE_AI_SEARCH_ENDPOINT}}
MONGODB_ATLAS_CONNECTION_STRING: ${{secrets.MONGODB_ATLAS_CONNECTION_STRING}}
AZURE_KEY_VAULT_ENDPOINT: ${{secrets.AZURE_KEY_VAULT_ENDPOINT}}
AZURE_KEY_VAULT_CLIENT_ID: ${{secrets.AZURE_KEY_VAULT_CLIENT_ID}}
AZURE_KEY_VAULT_CLIENT_SECRET: ${{secrets.AZURE_KEY_VAULT_CLIENT_SECRET}}
ACA_POOL_MANAGEMENT_ENDPOINT: ${{secrets.ACA_POOL_MANAGEMENT_ENDPOINT}}
MISTRALAI_API_KEY: ${{secrets.MISTRALAI_API_KEY}}
MISTRALAI_CHAT_MODEL_ID: ${{ vars.MISTRALAI_CHAT_MODEL_ID }}
MISTRALAI_EMBEDDING_MODEL_ID: ${{ vars.MISTRALAI_EMBEDDING_MODEL_ID }}
ANTHROPIC_API_KEY: ${{secrets.ANTHROPIC_API_KEY}}
ANTHROPIC_CHAT_MODEL_ID: ${{ vars.ANTHROPIC_CHAT_MODEL_ID }}
OLLAMA_CHAT_MODEL_ID: "${{ vars.OLLAMA_CHAT_MODEL_ID || '' }}" # llama3.2:1b
OLLAMA_CHAT_MODEL_ID_IMAGE: "${{ vars.OLLAMA_CHAT_MODEL_ID_IMAGE || '' }}" # moondream
OLLAMA_CHAT_MODEL_ID_TOOL_CALL: "${{ vars.OLLAMA_CHAT_MODEL_ID_TOOL_CALL || '' }}" # llama3.2:1b
OLLAMA_TEXT_MODEL_ID: "${{ vars.OLLAMA_TEXT_MODEL_ID || '' }}" # llama3.2:1b
OLLAMA_EMBEDDING_MODEL_ID: "${{ vars.OLLAMA_EMBEDDING_MODEL_ID || '' }}" # nomic-embed-text
GOOGLE_AI_GEMINI_MODEL_ID: ${{ vars.GOOGLE_AI_GEMINI_MODEL_ID }}
GOOGLE_AI_EMBEDDING_MODEL_ID: ${{ vars.GOOGLE_AI_EMBEDDING_MODEL_ID }}
GOOGLE_AI_API_KEY: ${{ secrets.GOOGLE_AI_API_KEY }}
GOOGLE_AI_CLOUD_PROJECT_ID: ${{ vars.GOOGLE_AI_CLOUD_PROJECT_ID }}
GOOGLE_AI_CLOUD_REGION: ${{ vars.GOOGLE_AI_CLOUD_REGION }}
VERTEX_AI_PROJECT_ID: ${{ vars.VERTEX_AI_PROJECT_ID }}
VERTEX_AI_GEMINI_MODEL_ID: ${{ vars.VERTEX_AI_GEMINI_MODEL_ID }}
VERTEX_AI_EMBEDDING_MODEL_ID: ${{ vars.VERTEX_AI_EMBEDDING_MODEL_ID }}
REDIS_CONNECTION_STRING: ${{ vars.REDIS_CONNECTION_STRING }}
AZURE_COSMOS_DB_NO_SQL_URL: ${{ vars.AZURE_COSMOS_DB_NO_SQL_URL }}
AZURE_COSMOS_DB_NO_SQL_KEY: ${{ secrets.AZURE_COSMOS_DB_NO_SQL_KEY }}
BEDROCK_AGENT_AGENT_RESOURCE_ROLE_ARN: ${{ secrets.BEDROCK_AGENT_AGENT_RESOURCE_ROLE_ARN }}
BEDROCK_AGENT_FOUNDATION_MODEL: ${{ vars.BEDROCK_AGENT_FOUNDATION_MODEL }}
jobs:
paths-filter:
runs-on: ubuntu-latest
outputs:
pythonChanges: ${{ steps.filter.outputs.python}}
steps:
- uses: actions/checkout@v5
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
python:
- 'python/**'
# run only if 'python' files were changed
- name: python tests
if: steps.filter.outputs.python == 'true'
run: echo "Python file"
# run only if not 'python' files were changed
- name: not python tests
if: steps.filter.outputs.python != 'true'
run: echo "NOT python file"
python-merge-gate-ai-services:
name: Python Pre-Merge Integration Tests - AI Services (incl samples using those)
needs: paths-filter
if: github.event_name != 'pull_request' && github.event_name != 'schedule' && needs.paths-filter.outputs.pythonChanges == 'true'
strategy:
max-parallel: 1
fail-fast: false
matrix:
python-version: ["3.11"]
os: [ubuntu-latest]
defaults:
run:
working-directory: python
runs-on: ${{ matrix.os }}
environment: "integration"
env:
UV_PYTHON: ${{ matrix.python-version }}
COMPLETIONS_CONCEPT_SAMPLE: "true"
steps:
- uses: actions/checkout@v5
- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
version: "0.5.x"
enable-cache: true
cache-suffix: ${{ runner.os }}-${{ matrix.python-version }}
cache-dependency-glob: "**/uv.lock"
- name: Install dependencies
run: |
uv sync --all-extras --dev
- name: Google auth
uses: google-github-actions/auth@v3
with:
project_id: ${{ vars.VERTEX_AI_PROJECT_ID }}
credentials_json: ${{ secrets.VERTEX_AI_SERVICE_ACCOUNT_KEY }}
- name: Set up gcloud
uses: google-github-actions/setup-gcloud@v3
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v5
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
- name: Azure CLI Login
if: github.event_name != 'pull_request'
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Run Integration Tests
id: run_tests_ai_services
shell: bash
run: |
uv run pytest -v --log-cli-level=INFO --durations=20 -n logical --dist loadfile --dist worksteal -m "not ollama" ./tests/integration/completions ./tests/integration/embeddings ./tests/samples ./tests/integration/cross_language
python-merge-gate-multi-modality:
name: Python Pre-Merge Integration Tests - Multi-Modality
needs: paths-filter
if: github.event_name != 'pull_request' && github.event_name != 'schedule' && needs.paths-filter.outputs.pythonChanges == 'true'
strategy:
max-parallel: 1
fail-fast: false
matrix:
python-version: ["3.11"]
os: [ubuntu-latest]
defaults:
run:
working-directory: python
runs-on: ${{ matrix.os }}
environment: "integration"
env:
UV_PYTHON: ${{ matrix.python-version }}
steps:
- uses: actions/checkout@v5
- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
version: "0.5.x"
enable-cache: true
cache-suffix: ${{ runner.os }}-${{ matrix.python-version }}
- name: Install dependencies
run: |
uv sync --all-extras --dev
- name: Azure CLI Login
if: github.event_name != 'pull_request'
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Run Integration Tests
id: run_tests_multi_modality
shell: bash
run: |
uv run pytest -v --log-cli-level=INFO --durations=20 -n logical --dist loadfile --dist worksteal ./tests/integration/audio_to_text ./tests/integration/text_to_audio ./tests/integration/text_to_image
python-merge-gate-agents:
name: Python Pre-Merge Integration Tests - Agents
needs: paths-filter
if: github.event_name != 'pull_request' && github.event_name != 'schedule' && needs.paths-filter.outputs.pythonChanges == 'true'
strategy:
max-parallel: 1
fail-fast: false
matrix:
python-version: ["3.11"]
os: [ubuntu-latest]
defaults:
run:
working-directory: python
runs-on: ${{ matrix.os }}
environment: "integration"
env:
UV_PYTHON: ${{ matrix.python-version }}
steps:
- uses: actions/checkout@v5
- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
version: "0.5.x"
enable-cache: true
cache-suffix: ${{ runner.os }}-${{ matrix.python-version }}
- name: Install dependencies
run: |
uv sync --all-extras --dev
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v5
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
- name: Azure CLI Login
if: github.event_name != 'pull_request'
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Run Integration Tests
id: run_tests_agents
shell: bash
run: |
uv run pytest -v --log-cli-level=INFO --durations=20 -n logical --dist loadfile --dist worksteal ./tests/integration/agents
python-merge-gate-ollama:
name: Python Pre-Merge Integration Tests - Ollama
needs: paths-filter
# Ollama tests are very unstable at the moment. It often fails to pull models from the Ollama server. Thus, this job is disabled for now.
if: false && github.event_name != 'pull_request' && github.event_name != 'schedule' && needs.paths-filter.outputs.pythonChanges == 'true'
strategy:
max-parallel: 1
fail-fast: false
matrix:
python-version: ["3.11"]
os: [ubuntu-latest]
defaults:
run:
working-directory: python
runs-on: ${{ matrix.os }}
environment: "integration"
env:
UV_PYTHON: ${{ matrix.python-version }}
COMPLETIONS_CONCEPT_SAMPLE: "true"
steps:
- uses: actions/checkout@v5
- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
version: "0.5.x"
enable-cache: true
cache-suffix: ${{ runner.os }}-${{ matrix.python-version }}
cache-dependency-glob: "**/uv.lock"
- name: Install dependencies
run: |
uv sync --all-extras --dev
- name: Install Ollama
if: matrix.os == 'ubuntu-latest'
run: |
curl -fsSL https://ollama.com/install.sh | sh
ollama serve &
sleep 5
- name: Pull model in Ollama
if: matrix.os == 'ubuntu-latest'
run: |
ollama pull ${{ vars.OLLAMA_CHAT_MODEL_ID }}
ollama pull ${{ vars.OLLAMA_CHAT_MODEL_ID_IMAGE }}
ollama pull ${{ vars.OLLAMA_CHAT_MODEL_ID_TOOL_CALL }}
ollama pull ${{ vars.OLLAMA_TEXT_MODEL_ID }}
ollama pull ${{ vars.OLLAMA_EMBEDDING_MODEL_ID }}
ollama list
- name: Run Integration Tests
id: run_tests_ai_services
shell: bash
run: |
uv run pytest -v --log-cli-level=INFO --durations=0 -n logical --dist loadfile --dist worksteal -m ollama --timeout=300 ./tests/integration/completions ./tests/integration/embeddings
python-merge-gate-memory:
name: Python Pre-Merge Integration Tests - Memory (incl samples using those)
needs: paths-filter
if: github.event_name != 'pull_request' && github.event_name != 'schedule' && needs.paths-filter.outputs.pythonChanges == 'true'
strategy:
max-parallel: 1
fail-fast: false
matrix:
python-version: ["3.11"]
os: [ubuntu-latest]
defaults:
run:
working-directory: python
runs-on: ${{ matrix.os }}
environment: "integration"
env:
UV_PYTHON: ${{ matrix.python-version }}
MEMORY_CONCEPT_SAMPLE: "true"
# Service containers to run with for the memory connectors, this only works on Ubuntu
services:
# Label used to access the service container
redis:
# Docker Hub image
image: redis/redis-stack-server:latest
ports:
# Opens tcp port 6379 on the host and service container
- 6379:6379
weaviate:
image: cr.weaviate.io/semitechnologies/weaviate:1.33.3
ports:
- 8080:8080
- 50051:50051
steps:
- uses: actions/checkout@v5
- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
version: "0.5.x"
enable-cache: true
cache-suffix: ${{ runner.os }}-${{ matrix.python-version }}
cache-dependency-glob: "**/uv.lock"
- name: Install dependencies
run: |
uv sync --all-extras --dev
- name: Azure CLI Login
if: github.event_name != 'pull_request'
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Run Integration Tests
id: run_tests_memory
timeout-minutes: 15
shell: bash
run: |
uv run pytest -v --log-cli-level=INFO --durations=20 -n logical --dist loadfile --dist worksteal ./tests/integration/memory ./tests/samples
python-integration-tests:
name: Python Integration Tests - Scheduled run
needs: paths-filter
if: (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && needs.paths-filter.outputs.pythonChanges == 'true'
strategy:
max-parallel: 1
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12"]
os: [ubuntu-latest, windows-latest, macos-latest]
defaults:
run:
working-directory: python
runs-on: ${{ matrix.os }}
env:
UV_PYTHON: ${{ matrix.python-version }}
MEMORY_CONCEPT_SAMPLE: "true"
COMPLETIONS_CONCEPT_SAMPLE: "true"
# Service containers to run with for the memory connectors, this only works on Ubuntu
services:
# Label used to access the service container
redis:
# Docker Hub image
image: redis/redis-stack-server:latest
ports:
# Opens tcp port 6379 on the host and service container
- 6379:6379
weaviate:
image: cr.weaviate.io/semitechnologies/weaviate:1.26.6
ports:
- 8080:8080
- 50051:50051
steps:
- uses: actions/checkout@v5
- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
version: "0.5.x"
enable-cache: true
cache-suffix: ${{ runner.os }}-${{ matrix.python-version }}
cache-dependency-glob: "**/uv.lock"
- name: Install dependencies
run: |
uv sync --all-extras --dev
- name: Install Ollama
if: matrix.os == 'ubuntu-latest'
run: |
curl -fsSL https://ollama.com/install.sh | sh
ollama serve &
sleep 5
- name: Pull model in Ollama
# Ollama tests are very unstable at the moment. It often fails to pull models from the Ollama server. Thus, Ollama is disabled for now.
if: false && matrix.os == 'ubuntu-latest'
run: |
ollama pull ${{ vars.OLLAMA_CHAT_MODEL_ID }}
ollama pull ${{ vars.OLLAMA_CHAT_MODEL_ID_IMAGE }}
ollama pull ${{ vars.OLLAMA_CHAT_MODEL_ID_TOOL_CALL }}
ollama pull ${{ vars.OLLAMA_TEXT_MODEL_ID }}
ollama pull ${{ vars.OLLAMA_EMBEDDING_MODEL_ID }}
ollama list
- name: Google auth
uses: google-github-actions/auth@v3
with:
project_id: ${{ vars.VERTEX_AI_PROJECT_ID }}
credentials_json: ${{ secrets.VERTEX_AI_SERVICE_ACCOUNT_KEY }}
- name: Set up gcloud
uses: google-github-actions/setup-gcloud@v3
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v5
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
- name: Start Azure Cosmos DB emulator
if: matrix.os == 'windows-latest'
run: |
Write-Host "Launching Cosmos DB Emulator"
Import-Module "$env:ProgramFiles\Azure Cosmos DB Emulator\PSModules\Microsoft.Azure.CosmosDB.Emulator"
Start-CosmosDbEmulator
- name: Azure CLI Login
if: github.event_name != 'pull_request'
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Run Integration Tests - Completions
id: run_tests_completions
timeout-minutes: 10
shell: bash
# Ollama tests are very unstable at the moment. It often fails to pull models from the Ollama server. Thus, Ollama is disabled for now.
run: |
uv run pytest -v -n logical --dist loadfile --dist worksteal -m "not ollama" ./tests/integration/completions
- name: Run Integration Tests - Embeddings
id: run_tests_embeddings
timeout-minutes: 5
shell: bash
# Ollama tests are very unstable at the moment. It often fails to pull models from the Ollama server. Thus, Ollama is disabled for now.
run: |
uv run pytest -v -n logical --dist loadfile --dist worksteal -m "not ollama" ./tests/integration/embeddings
- name: Run Integration Tests - Memory
id: run_tests_memory
timeout-minutes: 5
shell: bash
run: |
uv run pytest -v -n logical --dist loadfile --dist worksteal ./tests/integration/memory
- name: Run Integration Tests - Cross Language
id: run_tests_cross_language
timeout-minutes: 5
shell: bash
run: |
uv run pytest -v -n logical --dist loadfile --dist worksteal ./tests/integration/cross_language
- name: Run Integration Tests - Planning
id: run_tests_planning
timeout-minutes: 5
shell: bash
run: |
uv run pytest -v -n logical --dist loadfile --dist worksteal ./tests/integration/planning
- name: Run Integration Tests - Samples
id: run_tests_samples
timeout-minutes: 5
shell: bash
run: |
uv run pytest -v -n logical --dist loadfile --dist worksteal ./tests/samples
- name: Run Integration Tests - Agents
id: run_tests_agents
timeout-minutes: 10
shell: bash
run: |
uv run pytest -v -n logical --dist loadfile --dist worksteal ./tests/integration/agents
- name: Run Integration Tests - Multi-Modality
id: run_tests_multi_modality
timeout-minutes: 5
shell: bash
run: |
uv run pytest -v -n logical --dist loadfile --dist worksteal ./tests/integration/audio_to_text ./tests/integration/text_to_audio ./tests/integration/text_to_image
# This final job is required to satisfy the merge queue. It must only run (or succeed) if no tests failed
python-integration-tests-check:
if: always()
runs-on: ubuntu-latest
strategy:
max-parallel: 1
fail-fast: false
needs:
[
python-merge-gate-ai-services,
python-merge-gate-ollama,
python-merge-gate-memory,
python-merge-gate-agents,
python-merge-gate-multi-modality,
python-integration-tests,
]
steps:
- name: Get Date
shell: bash
run: |
echo "date=$(date +'%m/%d/%Y %H:%M:%S')" >> "$GITHUB_ENV"
- name: Run Type is Daily
if: ${{ github.event_name == 'schedule' }}
shell: bash
run: |
echo "run_type=Daily" >> "$GITHUB_ENV"
- name: Run Type is Manual
if: ${{ github.event_name == 'workflow_dispatch' }}
shell: bash
run: |
echo "run_type=Manual" >> "$GITHUB_ENV"
- name: Run Type is ${{ github.event_name }}
if: ${{ github.event_name != 'schedule' && github.event_name != 'workflow_dispatch'}}
shell: bash
run: |
echo "run_type=${{ github.event_name }}" >> "$GITHUB_ENV"
- name: Fail workflow if tests failed
id: check_tests_failed
if: contains(join(needs.*.result, ','), 'failure')
uses: actions/github-script@v6
with:
script: core.setFailed('Integration Tests Failed!')
- name: Fail workflow if tests cancelled
id: check_tests_cancelled
if: contains(join(needs.*.result, ','), 'cancelled')
uses: actions/github-script@v6
with:
script: core.setFailed('Integration Tests Cancelled!')
- name: Microsoft Teams Notification
uses: skitionek/notify-microsoft-teams@v1.0.9
if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
with:
webhook_url: ${{ secrets.MSTEAMS_WEBHOOK }}
dry_run: ${{ env.run_type != 'Daily' && env.run_type != 'Manual'}}
job: ${{ toJson(job) }}
steps: ${{ toJson(steps) }}
title: "{title: ` ${{ env.run_type }}: ${{ env.date }} `, text: ` ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}`}"
- name: Microsoft Teams Notification (Dry Run)
uses: skitionek/notify-microsoft-teams@v1.0.9
if: github.ref != 'refs/heads/main'
with:
webhook_url: NONE
dry_run: ${{ env.run_type != 'Daily' && env.run_type != 'Manual'}}
job: ${{ toJson(job) }}
steps: ${{ toJson(steps) }}
title: "{title: ` ${{ env.run_type }}: ${{ env.date }} `, text: ` ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}`}"
python-lint matrix .github/workflows/python-lint.yml
View raw YAML
name: Python Code Quality Checks
on:
workflow_dispatch:
pull_request:
branches: ["main", "feature*"]
paths:
- "python/**"
jobs:
pre-commit:
if: "!cancelled()"
strategy:
fail-fast: false
matrix:
python-version: ["3.10"]
runs-on: ubuntu-latest
continue-on-error: true
defaults:
run:
working-directory: python
env:
# Configure a constant location for the uv cache
UV_CACHE_DIR: /tmp/.uv-cache
UV_PYTHON: ${{ matrix.python-version }}
steps:
- uses: actions/checkout@v5
- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
version: "0.5.x"
enable-cache: true
cache-suffix: ${{ runner.os }}-${{ matrix.python-version }}
cache-dependency-glob: "**/uv.lock"
- name: Install the project
run: uv sync --all-extras --dev
- uses: pre-commit/action@v3.0.1
name: Run Pre-Commit Hooks
with:
extra_args: --config python/.pre-commit-config.yaml --all-files
- name: Run Mypy
run: uv run mypy -p semantic_kernel --config-file mypy.ini
python-manual-release perms .github/workflows/python-manual-release.yml
View raw YAML
name: Python Start Release on ADO
on:
workflow_dispatch:
inputs:
tag:
description: "Tag to release"
required: true
permissions:
contents: read
id-token: write
jobs:
python-start-ado-release-job:
name: Trigger ADO Pipeline for Python Release
runs-on: ubuntu-latest
environment: "integration"
steps:
- name: Azure Login
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Start DevOps pipeline
uses: azure/cli@v2
with:
inlineScript: |
az pipelines run --id ${{ vars.ADO_PYTHON_RELEASE_ID }} --org ${{ vars.ADO_ORG }} --project ${{ vars.ADO_PROJECT_NAME }} --parameters tag=${{ inputs.tag }} delay=0
python-test-coverage .github/workflows/python-test-coverage.yml
View raw YAML
name: Python Test Coverage
on:
pull_request:
branches: ["main", "feature*"]
paths:
- "python/semantic_kernel/**"
- "python/tests/unit/**"
env:
# Configure a constant location for the uv cache
UV_CACHE_DIR: /tmp/.uv-cache
jobs:
python-tests-coverage:
runs-on: ubuntu-latest
continue-on-error: false
defaults:
run:
working-directory: python
env:
UV_PYTHON: "3.10"
steps:
- uses: actions/checkout@v5
# Save the PR number to a file since the workflow_run event
# in the coverage report workflow does not have access to it
- name: Save PR number
run: |
echo ${{ github.event.number }} > ./pr_number
- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
version: "0.5.x"
enable-cache: true
cache-suffix: ${{ runner.os }}-${{ env.UV_PYTHON }}
cache-dependency-glob: "**/uv.lock"
- name: Install the project
run: uv sync --all-extras --dev -U --prerelease=if-necessary-or-explicit
- name: Test with pytest
run: uv run --frozen pytest -q --junitxml=pytest.xml --cov=semantic_kernel --cov-report=term-missing:skip-covered --cov-report=xml:python-coverage.xml ./tests/unit --ignore=./tests/unit/processes/dapr_runtime
- name: Upload coverage report
uses: actions/upload-artifact@v4
with:
path: |
python/python-coverage.xml
python/pytest.xml
python/pr_number
overwrite: true
retention-days: 1
if-no-files-found: error
python-test-coverage-report perms .github/workflows/python-test-coverage-report.yml
View raw YAML
name: Python Test Coverage Report
on:
workflow_run:
workflows: ["Python Test Coverage"]
types:
- completed
permissions:
contents: read
pull-requests: write
jobs:
python-test-coverage-report:
runs-on: ubuntu-latest
if: github.event.workflow_run.conclusion == 'success'
continue-on-error: false
defaults:
run:
working-directory: python
steps:
- uses: actions/checkout@v5
- name: Download coverage report
uses: actions/download-artifact@v5
with:
github-token: ${{ secrets.GH_ACTIONS_PR_WRITE }}
run-id: ${{ github.event.workflow_run.id }}
path: ./python
merge-multiple: true
- name: Display structure of downloaded files
run: ls
- name: Read and set PR number
# Need to read the PR number from the file saved in the previous workflow
# because the workflow_run event does not have access to the PR number
# The PR number is needed to post the comment on the PR
run: |
PR_NUMBER=$(cat pr_number)
echo "PR number: $PR_NUMBER"
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV
- name: Pytest coverage comment
id: coverageComment
uses: MishaKav/pytest-coverage-comment@v1.1.57
with:
github-token: ${{ secrets.GH_ACTIONS_PR_WRITE }}
issue-number: ${{ env.PR_NUMBER }}
pytest-xml-coverage-path: python/python-coverage.xml
title: "Python Test Coverage Report"
badge-title: "Python Test Coverage"
junitxml-title: "Python Unit Test Overview"
junitxml-path: python/pytest.xml
default-branch: "main"
report-only-changed-files: true
python-unit-tests matrix .github/workflows/python-unit-tests.yml
View raw YAML
name: Python Unit Tests
on:
pull_request:
branches: ["main", "feature*"]
paths:
- "python/**"
env:
# Configure a constant location for the uv cache
UV_CACHE_DIR: /tmp/.uv-cache
jobs:
python-unit-tests:
name: Python Unit Tests
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.experimental }}
strategy:
fail-fast: true
matrix:
python-version: ["3.10", "3.11", "3.12"]
os: [ubuntu-latest, windows-latest, macos-latest]
experimental: [false]
test-suite: ["unit-all-except-dapr", "dapr"]
exclude:
- python-version: "3.10"
os: macos-latest
- python-version: "3.11"
os: macos-latest
include:
- python-version: "3.13"
os: "ubuntu-latest"
experimental: true
test-suite: "unit-all-except-dapr"
env:
UV_PYTHON: ${{ matrix.python-version }}
permissions:
contents: write
defaults:
run:
working-directory: python
steps:
- uses: actions/checkout@v5
- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
version: "0.5.x"
enable-cache: true
cache-suffix: ${{ runner.os }}-${{ matrix.python-version }}
cache-dependency-glob: "**/uv.lock"
- name: Install the project (all extras)
if: matrix.test-suite == 'unit-all-except-dapr'
run: uv sync --all-extras --dev -U --prerelease=if-necessary-or-explicit
- name: Install the project (dapr tests)
if: matrix.test-suite == 'dapr'
run: uv sync --extra pandas --dev -U --prerelease=if-necessary-or-explicit && uv pip install "dapr>=1.14.0" "dapr-ext-fastapi>=1.14.0" "flask-dapr>=1.14.0"
- name: Test with pytest (all except dapr)
if: matrix.test-suite == 'unit-all-except-dapr'
env:
PYTHON_GIL: ${{ matrix.gil }}
run: uv run --frozen pytest --junitxml=pytest.xml ./tests/unit --ignore=tests/unit/processes/dapr_runtime
- name: Test dapr with pytest
if: matrix.test-suite == 'dapr'
env:
PYTHON_GIL: ${{ matrix.gil }}
run: uv run --frozen pytest --junitxml=pytest-dapr.xml ./tests/unit/processes/dapr_runtime
- name: Surface failing tests
if: ${{ !matrix.experimental && matrix.test-suite == 'unit-all-except-dapr' }}
uses: pmeier/pytest-results-action@v0.7.2
with:
path: python/pytest.xml
summary: true
display-options: fEX
fail-on-empty: true
title: Test results
typos .github/workflows/typos.yaml
View raw YAML
# Check pull requests for typos.
#
# Configuration: .github/_typos.toml
#
# Info: https://github.com/marketplace/actions/typos-action
# Local install: brew install typos-cli
# Local install: conda install typos
# Local run: typos -c .github/_typos.toml
name: Spell Check
on:
workflow_dispatch:
pull_request:
branches: ["main", "feature*"]
jobs:
run:
name: Spell Check with Typos
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v5
with:
persist-credentials: false
- name: Use custom config file
uses: crate-ci/typos@v1.36.2
with:
config: .github/_typos.toml
write_changes: false