microsoft / microsoft/aspire

.env is sorted alphabetically, leading to environment placeholders breaking

Open
#13,067 4 comments 0 reactions 0 assignees View on GitHub
‼️regression-from-last-release area-deployment docker-compose silent-failure
Dominant language
C#
Stars
6.3k
Forks
991
Avg merge
2d 15h
Merged PRs (30d)
196

Description

### Is there an existing issue for this?

- [x] I have searched the existing issues

### Describe the bug

Not sure if this is already resolved by #12656. 13.0 sorts the .env file alphabetically which destroys cross references made using `AsEnvironmentPlaceholder` in `PublishAsDockerComposeService`. With 9.5, the order is preserved and existing .env variables on top were kept. This is related to #12009 which now broke.

I use it to ensure the docker compose create the image in the form of `image: "${ABC_DOCKER_REPOSITORY}:${ABC_IMAGE_TAG:-2.12.44}"`.

```cs
var interfaceDockerRepositoryParam = builder.AddParameter("interface-docker-repository", "${DOCKER_REGISTRY_HOSTNAME}/myPrefix/", true)
...
// Workaround since resource.AddEnvironmentVariable is not accessible...
static ParameterResource GetUntrackedParameter(string name, string value)
{
return new ParameterResource(name, _ => value)
{
// This is necessary, as https://github.com/dotnet/aspire/blob/88da0b94e248d131a8b333bebd4c98031ef35f7f/src/Aspire.Hosting.Docker/DockerComposePublishingContext.cs#L184
// checks for Default to be set, which makes no sense...
// Default is only meant to allow the value to be added to the manifest. The GetValueAsync would work either way...
Default = new GenerateParameterDefault()
};
}
...
var repositoryName = $"{interfaceDockerRepositoryParam.AsEnvironmentPlaceholder(resource)}{resource.Name}";
var resourceDockerRepoParam = GetUntrackedParameter(resource.Name + "-docker-repository", repositoryName);
var resourceImageTagParam = GetUntrackedParameter(resource.Name + "-image-tag", string.Empty);

// Get environment names:
var resourceDockerRepoEnvName = resourceDockerRepoParam.AsEnvironmentPlaceholder(resource)[2..^1];
var resourceImageTagEnvName = resourceImageTagParam.AsEnvironmentPlaceholder(resource)[2..^1];
service.Image = $"${{{resourceDockerRepoEnvName}}}:${{{resourceImageTagEnvName}:-{fallbackVersion}}}";
```

If the `resource.Name` is alphabetically after `INTERFACE_DOCKER_REPOSITORY`, the reference will work. If not, the reference can't be resolved on startup...

In the past, this was created as
```
INTERFACE_DOCKER_REPOSITORY=${DOCKER_REGISTRY_HOSTNAME}/myPrefix/
ABC_DOCKER_REPOSITORY=${INTERFACE_DOCKER_REPOSITORY}/abc
ABC_IMAGE_TAG=
```
now it is created as
```
ABC_DOCKER_REPOSITORY=${INTERFACE_DOCKER_REPOSITORY}/abc
ABC_IMAGE_TAG=
INTERFACE_DOCKER_REPOSITORY=${DOCKER_REGISTRY_HOSTNAME}/myPrefix/
```
with INTERFACE_DOCKER_REPOSITORY failing to resolve.

### Expected Behavior

The .env file is created as until 9.5 with existing user variables being kept and order working in regards to the placeholders.

### Steps To Reproduce

1. Create a prameter as described above
2. Use it in PublishAsDockerComposeService as placeholder
3. Run `aspire do prepare-compose`
4. Start the docker-compose

### Exceptions (if any)

WARN[0000] The "INTERFACE_DOCKER_REPOSITORY" variable is not set. Defaulting to a blank string.

### .NET Version info

.NET SDK:
Version: 10.0.100
Commit: b0f34d51fc
Workload version: 10.0.100.1
MSBuild version: 18.0.2+b0f34d51f

Runtime Environment:
OS Name: Mac OS X
OS Version: 26.1
OS Platform: Darwin
RID: osx-arm64
Base Path: /usr/local/share/dotnet/sdk/10.0.100/

.NET workloads installed:
There are no installed workloads to display.
Configured to use workload sets when installing new manifests.

Host:
Version: 10.0.0
Architecture: arm64
Commit: b0f34d51fc

.NET SDKs installed:
9.0.307 [/usr/local/share/dotnet/sdk]
9.0.308 [/usr/local/share/dotnet/sdk]
10.0.100 [/usr/local/share/dotnet/sdk]

.NET runtimes installed:
Microsoft.AspNetCore.App 9.0.11 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 10.0.0 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 9.0.11 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
Microsoft.NETCore.App 10.0.0 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]

Other architectures found:
None

Environment variables:
DOTNET_INSTALL_DIR [/usr/local/share/dotnet/]

global.json file:
/Users//GitRepos//global.json

Learn more:
https://aka.ms/dotnet/info

Download .NET:
https://aka.ms/dotnet/download

### Anything else?

ASP.NET Core: 10.0.100
.NET Aspire: 10.0.0
IDE: Rider

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.