-
Notifications
You must be signed in to change notification settings - Fork 884
Fail on JavaScript run script Dockerfile conflict #16969
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
e9dca1a
4ca0c7a
404e13b
02cec45
d182e0c
df796c4
64ea719
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,7 @@ | |
| using Aspire.Hosting.ApplicationModel.Docker; | ||
| using Aspire.Hosting.JavaScript; | ||
| using Aspire.Hosting.Pipelines; | ||
| using Aspire.Hosting.Publishing; | ||
| using Aspire.Hosting.Utils; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using Microsoft.Extensions.Hosting; | ||
|
|
@@ -29,6 +30,8 @@ public static class JavaScriptHostingExtensions | |
| { | ||
| private const string BrowserCapability = "browser"; | ||
| private const string DefaultNodeVersion = "22"; | ||
| private const string DefaultJavaScriptRunScriptName = "dev"; | ||
| private const string PublishManifestStepName = "publish-manifest"; | ||
| private const string DefaultYarpImage = Yarp.YarpContainerImageTags.Registry + "/" + Yarp.YarpContainerImageTags.Image + ":" + Yarp.YarpContainerImageTags.Tag; | ||
|
|
||
| // This is the order of config files that Vite will look for by default | ||
|
|
@@ -329,7 +332,7 @@ private static IResourceBuilder<TResource> WithNodeDefaults<TResource>(this IRes | |
| /// integration. | ||
| /// </remarks> | ||
| [AspireExport(Description = "Adds a JavaScript application resource")] | ||
| public static IResourceBuilder<JavaScriptAppResource> AddJavaScriptApp(this IDistributedApplicationBuilder builder, [ResourceName] string name, string appDirectory, string runScriptName = "dev") | ||
| public static IResourceBuilder<JavaScriptAppResource> AddJavaScriptApp(this IDistributedApplicationBuilder builder, [ResourceName] string name, string appDirectory, string runScriptName = DefaultJavaScriptRunScriptName) | ||
| { | ||
| ArgumentNullException.ThrowIfNull(builder); | ||
| ArgumentException.ThrowIfNullOrEmpty(name); | ||
|
|
@@ -873,6 +876,42 @@ private static IResourceBuilder<TResource> CreateDefaultJavaScriptAppBuilder<TRe | |
| .WithBuildScript("build") | ||
| .WithRunScript(runScriptName); | ||
|
|
||
| if (builder.ExecutionContext.IsPublishMode && | ||
| builder.TryCreateResourceBuilder<ContainerResource>(resource.Name, out var containerBuilder)) | ||
| { | ||
| var validationStepName = $"validate-javascript-dockerfile-run-script-{resource.Name}"; | ||
|
|
||
| Task WriteValidatedContainerAsync(ManifestPublishingContext context) | ||
| { | ||
| ValidateExistingDockerfileRunScript(resource, containerBuilder.Resource, runScriptName); | ||
| return context.WriteContainerAsync(containerBuilder.Resource); | ||
| } | ||
|
|
||
| resourceBuilder.WithManifestPublishingCallback(WriteValidatedContainerAsync); | ||
| containerBuilder.WithManifestPublishingCallback(WriteValidatedContainerAsync); | ||
| containerBuilder.WithAnnotation(new PipelineStepAnnotation(_ => new PipelineStep | ||
| { | ||
| Name = validationStepName, | ||
| Description = $"Validates that JavaScript app '{resource.Name}' does not publish an ignored run script with an existing Dockerfile.", | ||
| RequiredBySteps = [WellKnownPipelineSteps.Build, WellKnownPipelineSteps.Publish], | ||
| Resource = containerBuilder.Resource, | ||
| Action = _ => | ||
| { | ||
| ValidateExistingDockerfileRunScript(resource, containerBuilder.Resource, runScriptName); | ||
| return Task.CompletedTask; | ||
| } | ||
| })); | ||
| containerBuilder.WithAnnotation(new PipelineConfigurationAnnotation(context => | ||
| { | ||
| var validationStep = context.Steps.FirstOrDefault(s => string.Equals(s.Name, validationStepName, StringComparison.Ordinal)); | ||
| var publishManifestStep = context.Steps.FirstOrDefault(s => string.Equals(s.Name, PublishManifestStepName, StringComparison.Ordinal)); | ||
| if (validationStep is not null && publishManifestStep is not null) | ||
| { | ||
| validationStep.RequiredBy(publishManifestStep); | ||
| } | ||
| })); | ||
| } | ||
|
|
||
| resourceBuilder.WithVSCodeDebugging(); | ||
|
|
||
| // ensure the package manager command is set before starting the resource | ||
|
|
@@ -892,6 +931,40 @@ private static IResourceBuilder<TResource> CreateDefaultJavaScriptAppBuilder<TRe | |
| return resourceBuilder; | ||
| } | ||
|
|
||
| private static void ValidateExistingDockerfileRunScript(JavaScriptAppResource resource, ContainerResource containerResource, string initialRunScriptName) | ||
| { | ||
| if (containerResource.Entrypoint is not null || | ||
| !containerResource.TryGetLastAnnotation<DockerfileBuildAnnotation>(out var dockerfileBuildAnnotation) || | ||
| dockerfileBuildAnnotation.DockerfileFactory is not null || | ||
| !containerResource.TryGetLastAnnotation<JavaScriptRunScriptAnnotation>(out var runScript)) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| var hasMultipleRunScriptAnnotations = | ||
| containerResource.TryGetAnnotationsOfType<JavaScriptRunScriptAnnotation>(out var runScriptAnnotations) && | ||
| runScriptAnnotations.Skip(1).Any(); | ||
|
|
||
| var hasExplicitRunScript = | ||
| !string.Equals(initialRunScriptName, DefaultJavaScriptRunScriptName, StringComparison.Ordinal) || | ||
| hasMultipleRunScriptAnnotations || | ||
| runScript.Args.Length > 0; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
builder.AddJavaScriptApp("js", appDir)
.WithBun()
.WithRunScript("dev"); // same as the defaultRepro (verified against this PR build with Suggested fix: compare the last |
||
|
|
||
| if (!hasExplicitRunScript) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| // Existing Dockerfiles are user-authored, so Aspire cannot safely assume that replacing | ||
| // their entrypoint with a package-manager script will work for the image shape. | ||
| // If the user provides an explicit container entrypoint above, honor it; otherwise fail | ||
| // instead of silently publishing an image that ignores the requested run script. | ||
| throw new DistributedApplicationException( | ||
| $"JavaScript app resource '{resource.Name}' is configured to run script '{runScript.ScriptName}', but publish is using the existing Dockerfile '{dockerfileBuildAnnotation.DockerfilePath}'. " + | ||
| "An existing Dockerfile entrypoint cannot be changed automatically from runScriptName or WithRunScript. " + | ||
| "Remove or rename the Dockerfile so Aspire can generate one, or call PublishAsDockerFile(...) and set the container entrypoint explicitly."); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
builder.AddJavaScriptApp("js", appDir) // default script: "dev"
.WithBun()
.WithRunScript("dev", new[] { "--port", "8080" });fails with Suggested fix: when the trigger is |
||
| } | ||
|
|
||
| /// <summary> | ||
| /// Adds a Vite app to the distributed application builder. | ||
| /// </summary> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before start? @eerhardt ?