chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
param (
|
||||
[string]$JsonReportPath,
|
||||
[double]$CoverageThreshold
|
||||
)
|
||||
|
||||
$jsonContent = Get-Content $JsonReportPath -Raw | ConvertFrom-Json
|
||||
$coverageBelowThreshold = $false
|
||||
|
||||
$nonExperimentalAssemblies = [System.Collections.Generic.HashSet[string]]::new()
|
||||
|
||||
$assembliesCollection = @(
|
||||
'Microsoft.SemanticKernel.Abstractions'
|
||||
'Microsoft.SemanticKernel.Core'
|
||||
'Microsoft.SemanticKernel.PromptTemplates.Handlebars'
|
||||
'Microsoft.SemanticKernel.Connectors.OpenAI'
|
||||
'Microsoft.SemanticKernel.Connectors.AzureOpenAI'
|
||||
'Microsoft.SemanticKernel.Yaml'
|
||||
'Microsoft.SemanticKernel.Agents.Abstractions'
|
||||
'Microsoft.SemanticKernel.Agents.Core'
|
||||
'Microsoft.SemanticKernel.Agents.OpenAI'
|
||||
)
|
||||
|
||||
foreach ($assembly in $assembliesCollection) {
|
||||
$nonExperimentalAssemblies.Add($assembly)
|
||||
}
|
||||
|
||||
function Get-FormattedValue {
|
||||
param (
|
||||
[float]$Coverage,
|
||||
[bool]$UseIcon = $false
|
||||
)
|
||||
$formattedNumber = "{0:N1}" -f $Coverage
|
||||
$icon = if (-not $UseIcon) { "" } elseif ($Coverage -ge $CoverageThreshold) { '✅' } else { '❌' }
|
||||
|
||||
return "$formattedNumber% $icon"
|
||||
}
|
||||
|
||||
$lineCoverage = $jsonContent.summary.linecoverage
|
||||
$branchCoverage = $jsonContent.summary.branchcoverage
|
||||
|
||||
$totalTableData = [PSCustomObject]@{
|
||||
'Metric' = 'Total Coverage'
|
||||
'Line Coverage' = Get-FormattedValue -Coverage $lineCoverage
|
||||
'Branch Coverage' = Get-FormattedValue -Coverage $branchCoverage
|
||||
}
|
||||
|
||||
$totalTableData | Format-Table -AutoSize
|
||||
|
||||
$assemblyTableData = @()
|
||||
|
||||
foreach ($assembly in $jsonContent.coverage.assemblies) {
|
||||
$assemblyName = $assembly.name
|
||||
$assemblyLineCoverage = $assembly.coverage
|
||||
$assemblyBranchCoverage = $assembly.branchcoverage
|
||||
|
||||
$isNonExperimentalAssembly = $nonExperimentalAssemblies -contains $assemblyName
|
||||
|
||||
if ($isNonExperimentalAssembly -and ($assemblyLineCoverage -lt $CoverageThreshold -or $assemblyBranchCoverage -lt $CoverageThreshold)) {
|
||||
$coverageBelowThreshold = $true
|
||||
}
|
||||
|
||||
$assemblyTableData += [PSCustomObject]@{
|
||||
'Assembly Name' = $assemblyName
|
||||
'Line' = Get-FormattedValue -Coverage $assemblyLineCoverage -UseIcon $isNonExperimentalAssembly
|
||||
'Branch' = Get-FormattedValue -Coverage $assemblyBranchCoverage -UseIcon $isNonExperimentalAssembly
|
||||
}
|
||||
}
|
||||
|
||||
$sortedTable = $assemblyTableData | Sort-Object {
|
||||
$nonExperimentalAssemblies -contains $_.'Assembly Name'
|
||||
} -Descending
|
||||
|
||||
$sortedTable | Format-Table -AutoSize
|
||||
|
||||
if ($coverageBelowThreshold) {
|
||||
Write-Host "Code coverage is lower than defined threshold: $CoverageThreshold. Stopping the task."
|
||||
exit 1
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
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 }}
|
||||
@@ -0,0 +1,70 @@
|
||||
# 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}}"
|
||||
@@ -0,0 +1,139 @@
|
||||
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
|
||||
@@ -0,0 +1,244 @@
|
||||
#
|
||||
# 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" | grep -v "MEVD.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" | grep -v "MEVD.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)" | grep -v "test/VectorData/" | 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!')
|
||||
@@ -0,0 +1,129 @@
|
||||
#
|
||||
# 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() }}
|
||||
@@ -0,0 +1,94 @@
|
||||
#
|
||||
# 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
|
||||
@@ -0,0 +1,67 @@
|
||||
#
|
||||
# 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() }}
|
||||
@@ -0,0 +1,107 @@
|
||||
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 }}"
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
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
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
# 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 }}"
|
||||
@@ -0,0 +1,73 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
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"
|
||||
@@ -0,0 +1,32 @@
|
||||
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
|
||||
@@ -0,0 +1,48 @@
|
||||
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
|
||||
@@ -0,0 +1,566 @@
|
||||
#
|
||||
# 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 }}`}"
|
||||
@@ -0,0 +1,41 @@
|
||||
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
|
||||
@@ -0,0 +1,30 @@
|
||||
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
|
||||
@@ -0,0 +1,57 @@
|
||||
name: Python Test Coverage Report
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Python Test Coverage"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: 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: ${{ github.token }}
|
||||
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)
|
||||
if ! [[ "$PR_NUMBER" =~ ^[0-9]+$ ]]; then
|
||||
echo "::error::PR number file contains invalid content"
|
||||
exit 1
|
||||
fi
|
||||
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: ${{ github.token }}
|
||||
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
|
||||
@@ -0,0 +1,49 @@
|
||||
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
|
||||
@@ -0,0 +1,74 @@
|
||||
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
|
||||
@@ -0,0 +1,48 @@
|
||||
param([string]$targetNetFramework)
|
||||
|
||||
$targetNetFramework = "net$targetNetFramework"
|
||||
|
||||
$rootDirectory = Get-Location
|
||||
|
||||
Write-Host "Publishing the SemanticKernel.AotTests application."
|
||||
|
||||
dotnet publish $rootDirectory/dotnet/src/SemanticKernel.AotTests/SemanticKernel.AotTests.csproj --framework $targetNetFramework | Tee-Object -Variable publishOutput
|
||||
|
||||
$warningFound = $false
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
Write-Host "Errors were detected while publishing the application. See the output for more details."
|
||||
Exit $LastExitCode
|
||||
}
|
||||
elseif ($publishOutput -like "*analysis warning IL*" -or $publishOutput -like "*analysis error IL*")
|
||||
{
|
||||
Write-Host "Native AOT analysis warnings were detected while publishing the application. See the output for more details."
|
||||
Exit 1
|
||||
}
|
||||
|
||||
Write-Host "The application was published successfully."
|
||||
|
||||
$runtime = $IsWindows ? "win-x64" : "linux-x64"
|
||||
|
||||
$appPublishDirectory = Join-Path -Path $rootDirectory -ChildPath dotnet/src/SemanticKernel.AotTests/bin/Release/$targetNetFramework/$runtime/publish
|
||||
|
||||
$appFileName = $IsWindows ? "SemanticKernel.AotTests.exe" : "SemanticKernel.AotTests"
|
||||
|
||||
$app = Join-Path -Path $appPublishDirectory -ChildPath $appFileName
|
||||
|
||||
Write-Host "Executing the SemanticKernel.AotTests application."
|
||||
|
||||
& $app
|
||||
|
||||
if ($LastExitCode -ne 0)
|
||||
{
|
||||
$testPassed = 1
|
||||
Write-Host "There was an error while executing the application. The Last Exit Code is: $LastExitCode"
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host "The application was executed successfully."
|
||||
}
|
||||
|
||||
Exit $testPassed
|
||||
@@ -0,0 +1,31 @@
|
||||
# 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
|
||||
Executable
+107
@@ -0,0 +1,107 @@
|
||||
#!/bin/bash
|
||||
|
||||
POSITIONAL_ARGS=()
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-f|--file)
|
||||
file="$2"
|
||||
shift # past argument
|
||||
shift # past value
|
||||
;;
|
||||
-p|--propsFile)
|
||||
propsFile="$2"
|
||||
shift # past argument
|
||||
shift # past value
|
||||
;;
|
||||
-b|--buildAndRevisionNumber)
|
||||
buildAndRevisionNumber="$2"
|
||||
shift # past argument
|
||||
shift # past value
|
||||
;;
|
||||
-*|--*)
|
||||
echo "Unknown option $1"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
POSITIONAL_ARGS+=("$1") # save positional arg
|
||||
shift # past argument
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters
|
||||
|
||||
if [ -z "$file" ]; then
|
||||
echo "ERROR: Parameter file (-f|--file) not provided"
|
||||
exit 1;
|
||||
elif [ ! -f "$file" ]; then
|
||||
echo "ERROR: file ${file} not found"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
if [ -n "$(cat $file | grep -i "<IsPackable>false</IsPackable>")" ]; then
|
||||
echo "Project is marked as NOT packable - skipping."
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
if [ -z "$propsFile" ]; then
|
||||
echo "ERROR: Parameter propsFile (-f|--file) not provided"
|
||||
exit 1;
|
||||
elif [ ! -f "$propsFile" ]; then
|
||||
echo "ERROR: propsFile ${file} not found"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
if [ -z "$buildAndRevisionNumber" ]; then
|
||||
echo "ERROR: Parameter buildAndRevisionNumber (-b|--buildAndRevisionNumber) not provided"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
propsVersionString=$(cat $propsFile | grep -i "<Version>");
|
||||
regex="<Version>([0-9.]*)<\/Version>"
|
||||
if [[ $propsVersionString =~ $regex ]]; then
|
||||
propsVersion=${BASH_REMATCH[1]}
|
||||
else
|
||||
echo "ERROR: Version tag not found in propsFile"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
if [ -z "$propsVersion" ]; then
|
||||
echo "ERROR: Version tag not found in propsFile"
|
||||
exit 1;
|
||||
elif [[ ! "$propsVersion" =~ ^0.* ]]; then
|
||||
echo "ERROR: Version expected to start with 0. Actual: ${propsVersion}"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
fullVersionString="${propsVersion}.${buildAndRevisionNumber}-preview"
|
||||
|
||||
if [[ ! "$fullVersionString" =~ ^0.* ]]; then
|
||||
echo "ERROR: Version expected to start with 0. Actual: ${fullVersionString}"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
echo "==== Project: ${file} ====";
|
||||
echo "propsFile = ${propsFile}"
|
||||
echo "buildAndRevisionNumber = ${buildAndRevisionNumber}"
|
||||
echo "version prefix from propsFile = ${propsVersion}"
|
||||
echo "full version string: ${fullVersionString}"
|
||||
|
||||
versionInProj=$(cat $file | grep -i "<Version>");
|
||||
if [ -n "$versionInProj" ]; then
|
||||
# Version tag already exists in the csproj. Let's replace it.
|
||||
echo "Updating version tag..."
|
||||
content=$(cat $file | sed --expression="s/<Version>\([0-9]*.[0-9]*\)<\/Version>/<Version>$fullVersionString<\/Version>/g");
|
||||
else
|
||||
# Version tag not found in the csproj. Let's add it.
|
||||
echo "Project is packable - adding version tag..."
|
||||
content=$(cat $file | sed --expression="s/<\/Project>/<PropertyGroup><Version>$fullVersionString<\/Version><\/PropertyGroup><\/Project>/g");
|
||||
fi
|
||||
|
||||
if [ $? -ne 0 ]; then exit 1; fi
|
||||
echo "$content" && echo "$content" > $file;
|
||||
if [ $? -ne 0 ]; then exit 1; fi
|
||||
|
||||
echo "DONE";
|
||||
echo "";
|
||||
Reference in New Issue
Block a user