Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ When running tests in automated environments (including Copilot agent), **always

```bash
# Correct - excludes quarantined tests (use this in automation)
dotnet.sh test tests/Project.Tests/Project.Tests.csproj --filter-not-trait "quarantined=true"
dotnet.sh test tests/Project.Tests/Project.Tests.csproj -- --filter-not-trait "quarantined=true"

# For specific test filters, combine with quarantine exclusion
dotnet.sh test tests/Project.Tests/Project.Tests.csproj -- --filter "TestName" --filter-not-trait "quarantined=true"
Expand Down
6 changes: 6 additions & 0 deletions Aspire.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
<Project Path="src/Aspire.Hosting.AppHost/Aspire.Hosting.AppHost.csproj" />
<Project Path="src/Aspire.Hosting.Docker/Aspire.Hosting.Docker.csproj" />
<Project Path="src/Aspire.Hosting.Garnet/Aspire.Hosting.Garnet.csproj" />
<Project Path="src/Aspire.Hosting.GitHub.Models/Aspire.Hosting.GitHub.Models.csproj" />
<Project Path="src/Aspire.Hosting.Kafka/Aspire.Hosting.Kafka.csproj" />
<Project Path="src/Aspire.Hosting.Keycloak/Aspire.Hosting.Keycloak.csproj" />
<Project Path="src/Aspire.Hosting.Kubernetes/Aspire.Hosting.Kubernetes.csproj" />
Expand Down Expand Up @@ -163,6 +164,10 @@
<Project Path="playground/AspireEventHub/EventHubsApi/EventHubsApi.csproj" />
<Project Path="playground/AspireEventHub/EventHubsConsumer/EventHubsConsumer.csproj" />
</Folder>
<Folder Name="/playground/GitHubModelsEndToEnd/">
<Project Path="playground/GitHubModelsEndToEnd/GitHubModelsEndToEnd.AppHost/GitHubModelsEndToEnd.AppHost.csproj" />
<Project Path="playground/GitHubModelsEndToEnd/GitHubModelsEndToEnd.WebStory/GitHubModelsEndToEnd.WebStory.csproj" />
</Folder>
<Folder Name="/playground/ExternalServices/">
<Project Path="playground/ExternalServices/ExternalServices.AppHost/ExternalServices.AppHost.csproj" />
<Project Path="playground/ExternalServices/WebFrontEnd/WebFrontEnd.csproj" />
Expand Down Expand Up @@ -375,6 +380,7 @@
<Project Path="tests/Aspire.Hosting.Containers.Tests/Aspire.Hosting.Containers.Tests.csproj" />
<Project Path="tests/Aspire.Hosting.Docker.Tests/Aspire.Hosting.Docker.Tests.csproj" />
<Project Path="tests/Aspire.Hosting.Garnet.Tests/Aspire.Hosting.Garnet.Tests.csproj" />
<Project Path="tests/Aspire.Hosting.GitHub.Models.Tests/Aspire.Hosting.GitHub.Models.Tests.csproj" />
<Project Path="tests/Aspire.Hosting.Kafka.Tests/Aspire.Hosting.Kafka.Tests.csproj" />
<Project Path="tests/Aspire.Hosting.Keycloak.Tests/Aspire.Hosting.Keycloak.Tests.csproj" />
<Project Path="tests/Aspire.Hosting.Kubernetes.Tests/Aspire.Hosting.Kubernetes.Tests.csproj" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>$(DefaultTargetFramework)</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireHost>true</IsAspireHost>
<UserSecretsId>b8e8b8c7-4a45-4b2e-8c7d-9e8f7a6b5c4d</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<Compile Include="..\..\KnownResourceNames.cs" Link="KnownResourceNames.cs" />
</ItemGroup>

<ItemGroup>
<AspireProjectOrPackageReference Include="Aspire.Hosting.Azure.AppContainers" />
<AspireProjectOrPackageReference Include="Aspire.Hosting.AppHost" />
<AspireProjectOrPackageReference Include="Aspire.Hosting.GitHub.Models" />
<ProjectReference Include="..\GitHubModelsEndToEnd.WebStory\GitHubModelsEndToEnd.WebStory.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureContainerAppEnvironment("env");

var chat = builder.AddGitHubModel("chat", "openai/gpt-4o-mini");

// To set the GitHub Models API key define the value for the following parameter in User Secrets.
// Alternatively, you can set the environment variable GITHUB_TOKEN and comment the line below.
chat.WithApiKey(builder.AddParameter("github-api-key", secret: true));

builder.AddProject<Projects.GitHubModelsEndToEnd_WebStory>("webstory")
.WithExternalHttpEndpoints()
.WithReference(chat).WaitFor(chat);

#if !SKIP_DASHBOARD_REFERENCE
// This project is only added in playground projects to support development/debugging
// of the dashboard. It is not required in end developer code. Comment out this code
// or build with `/p:SkipDashboardReference=true`, to test end developer
// dashboard launch experience, Refer to Directory.Build.props for the path to
// the dashboard binary (defaults to the Aspire.Dashboard bin output in the
// artifacts dir).
builder.AddProject<Projects.Aspire_Dashboard>(KnownResourceNames.AspireDashboard);
#endif

builder.Build().Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:15215;http://localhost:15216",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:16195",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:17037"
}
},
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:15216",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:16195",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:17038",
"ASPIRE_ALLOW_UNSECURED_TRANSPORT": "true"
}
},
"generate-manifest": {
"commandName": "Project",
"launchBrowser": true,
"dotnetRunMessages": true,
"commandLineArgs": "--publisher manifest --output-path aspire-manifest.json",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"$schema": "https://json.schemastore.org/aspire-8.0.json",
"resources": {
"env": {
"type": "azure.bicep.v0",
"path": "env.module.bicep",
"params": {
"userPrincipalId": ""
}
},
"chat": {
"type": "value.v0",
"connectionString": "Endpoint=https://models.github.ai/inference;Key={github-api-key.value};Model=openai/gpt-4o-mini;DeploymentId=openai/gpt-4o-mini"
},
"github-api-key": {
"type": "parameter.v0",
"value": "{github-api-key.inputs.value}",
"inputs": {
"value": {
"type": "string",
"secret": true
}
}
},
"webstory": {
"type": "project.v1",
"path": "../GitHubModelsEndToEnd.WebStory/GitHubModelsEndToEnd.WebStory.csproj",
"deployment": {
"type": "azure.bicep.v0",
"path": "webstory.module.bicep",
"params": {
"env_outputs_azure_container_apps_environment_default_domain": "{env.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN}",
"env_outputs_azure_container_apps_environment_id": "{env.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_ID}",
"env_outputs_azure_container_registry_endpoint": "{env.outputs.AZURE_CONTAINER_REGISTRY_ENDPOINT}",
"env_outputs_azure_container_registry_managed_identity_id": "{env.outputs.AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID}",
"webstory_containerimage": "{webstory.containerImage}",
"webstory_containerport": "{webstory.containerPort}",
"github_api_key_value": "{github-api-key.value}"
}
},
"env": {
"OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES": "true",
"OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES": "true",
"OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY": "in_memory",
"ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true",
"HTTP_PORTS": "{webstory.bindings.http.targetPort}",
"ConnectionStrings__chat": "{chat.connectionString}"
},
"bindings": {
"http": {
"scheme": "http",
"protocol": "tcp",
"transport": "http",
"external": true
},
"https": {
"scheme": "https",
"protocol": "tcp",
"transport": "http",
"external": true
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location

param userPrincipalId string

param tags object = { }

resource env_mi 'Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30' = {
name: take('env_mi-${uniqueString(resourceGroup().id)}', 128)
location: location
tags: tags
}

resource env_acr 'Microsoft.ContainerRegistry/registries@2025-04-01' = {
name: take('envacr${uniqueString(resourceGroup().id)}', 50)
location: location
sku: {
name: 'Basic'
}
tags: tags
}

resource env_acr_env_mi_AcrPull 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(env_acr.id, env_mi.id, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d'))
properties: {
principalId: env_mi.properties.principalId
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')
principalType: 'ServicePrincipal'
}
scope: env_acr
}

resource env_law 'Microsoft.OperationalInsights/workspaces@2025-02-01' = {
name: take('envlaw-${uniqueString(resourceGroup().id)}', 63)
location: location
properties: {
sku: {
name: 'PerGB2018'
}
}
tags: tags
}

resource env 'Microsoft.App/managedEnvironments@2025-01-01' = {
name: take('env${uniqueString(resourceGroup().id)}', 24)
location: location
properties: {
appLogsConfiguration: {
destination: 'log-analytics'
logAnalyticsConfiguration: {
customerId: env_law.properties.customerId
sharedKey: env_law.listKeys().primarySharedKey
}
}
workloadProfiles: [
{
name: 'consumption'
workloadProfileType: 'Consumption'
}
]
}
tags: tags
}

resource aspireDashboard 'Microsoft.App/managedEnvironments/dotNetComponents@2024-10-02-preview' = {
name: 'aspire-dashboard'
properties: {
componentType: 'AspireDashboard'
}
parent: env
}

output AZURE_LOG_ANALYTICS_WORKSPACE_NAME string = env_law.name

output AZURE_LOG_ANALYTICS_WORKSPACE_ID string = env_law.id

output AZURE_CONTAINER_REGISTRY_NAME string = env_acr.name

output AZURE_CONTAINER_REGISTRY_ENDPOINT string = env_acr.properties.loginServer

output AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID string = env_mi.id

output AZURE_CONTAINER_APPS_ENVIRONMENT_NAME string = env.name

output AZURE_CONTAINER_APPS_ENVIRONMENT_ID string = env.id

output AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN string = env.properties.defaultDomain
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location

param env_outputs_azure_container_apps_environment_default_domain string

param env_outputs_azure_container_apps_environment_id string

param env_outputs_azure_container_registry_endpoint string

param env_outputs_azure_container_registry_managed_identity_id string

param webstory_containerimage string

param webstory_containerport string

@secure()
param github_api_key_value string

resource webstory 'Microsoft.App/containerApps@2025-02-02-preview' = {
name: 'webstory'
location: location
properties: {
configuration: {
secrets: [
{
name: 'connectionstrings--chat'
value: 'Endpoint=https://models.github.ai/inference;Key=${github_api_key_value};Model=openai/gpt-4o-mini;DeploymentId=openai/gpt-4o-mini'
}
]
activeRevisionsMode: 'Single'
ingress: {
external: true
targetPort: int(webstory_containerport)
transport: 'http'
}
registries: [
{
server: env_outputs_azure_container_registry_endpoint
identity: env_outputs_azure_container_registry_managed_identity_id
}
]
runtime: {
dotnet: {
autoConfigureDataProtection: true
}
}
}
environmentId: env_outputs_azure_container_apps_environment_id
template: {
containers: [
{
image: webstory_containerimage
name: 'webstory'
env: [
{
name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES'
value: 'true'
}
{
name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES'
value: 'true'
}
{
name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY'
value: 'in_memory'
}
{
name: 'ASPNETCORE_FORWARDEDHEADERS_ENABLED'
value: 'true'
}
{
name: 'HTTP_PORTS'
value: webstory_containerport
}
{
name: 'ConnectionStrings__chat'
secretRef: 'connectionstrings--chat'
}
]
}
]
scale: {
minReplicas: 1
}
}
}
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${env_outputs_azure_container_registry_managed_identity_id}': { }
}
}
}
Loading
Loading