Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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