Skip to content

Remove unsupported runtimes from SKU built-in profiles - #5507

Merged
sarah (satvu) merged 8 commits into
vnextfrom
satvu/update-builtin-profiles
Sep 17, 2026
Merged

sarah (satvu) merged 8 commits into
vnextfrom
satvu/update-builtin-profiles

Conversation

@satvu

@satvu sarah (satvu) commented Aug 4, 2026 •

Copy link
Copy Markdown
Member

Summary

Fixes #5293

Aligns built-in profiles with Azure runtime support and enforces supportedRuntimes during func start. Unsupported stacks are rejected before worker resolution or auto-install, with a second check against the resolved worker runtime.

Changes

Built-in profiles

Profile Removed from supportedRuntimes Removed from workers
windows-consumption python python, go
windows-dedicated python python, go
linux-premium — go
linux-consumption — go

The profiles continue to use dotnet-isolated, matching the .NET worker runtime identity consumed by func setup and the Functions host.

Runtime validation

  • Validates profile support before resolving or installing a worker, so missing or invalid worker installations do not mask unsupported-stack errors.
  • Retains validation against the actual runtime after worker resolution.
  • Accepts either the project stack name or worker runtime identity: .NET uses stack dotnet and runtime dotnet-isolated; Go uses stack/workload go and runtime native.
  • Reads the expected runtime from FunctionsWorkerReference and normalizes newly installed workers to that identity, preserving the worker ID, config path, and version. First-run Go workers therefore resolve as native, not go.
  • Reports unsupported stacks as user errors (exit code 1), including the profile's supported runtime list.

Tests and release notes

  • Covers rejection before worker resolution/installation with missing and invalid worker installations, asserting against IFunctionsWorkerInstaller.
  • Loads the shipped registry and asserts supported runtimes and worker keys for all five built-in profiles.
  • Covers .NET runtime matching and both go and native profile values during Go auto-install. The fake installer returns go; the final worker must be native with its metadata preserved.
  • Covers worker-reference runtime identities and updates src/Func/release_notes.md with the user-facing behavior change.

Supporting documentation

Python is Linux-only. The Azure Functions supported languages documentation marks Python as supported on Linux and unsupported on Windows. The Azure Functions scale and hosting documentation also states:

Linux is the only supported operating system for the Python runtime stack.

Go is Flex Consumption-only. The Go developer reference states:

Go support is currently available only for function apps hosted in the Flex Consumption plan.

Validation

Automated

  • dotnet test test\Func.Tests\Func.Tests.csproj --no-restore --filter "FullyQualifiedName~StartInitializationTests|FullyQualifiedName~FunctionsWorkerReferenceTests|FullyQualifiedName~BuiltInProfileSourceTests" -v minimal — 47 passed.
  • Release build with CI=true: dotnet build -c Release --no-restore -v q — succeeded with 0 warnings and 0 errors.

Manual — real workload packages

Built a Windows x64 CLI and real workload .nupkgs, published packages to a local NuGet v3 feed (http://localhost:5555/v3/index.json), and used an isolated CLI/workload home under artifacts\manual-go-test. Created a Go Functions project with func init --stack go. Runs used an interactive terminal so worker auto-install was enabled.

Scenario Procedure Observed result
Supported Go/Flex, worker missing Install real host and Go stack, remove Go worker, then run func start <app> --profile flex --output plain --no-azurite Auto-installed Go worker 1.0.0-local.20260916232418; reported Resolved worker native and resolve_worker complete: native.
Unsupported Go/Linux Premium, worker missing Republish the latest CLI at c046eded, remove Go worker, then run func start <app> --profile linux-premium --output plain --no-azurite Rejected with Profile 'linux-premium' does not support the 'Go' stack, listed supported runtimes, and exited with code 1. The workload list afterward still contained only the host and Go stack: no worker was installed.

Manual-test scope: The Flex run verified real-package auto-install and runtime normalization, not a complete host startup or function invocation. It stopped afterward at extension-bundle resolution because no compatible bundle workload was installed. Go was also unavailable on the test machine. The Linux Premium rejection occurred before those downstream dependencies were needed.

Remove python from supportedRuntimes and workers in windows-consumption and
windows-dedicated profiles. Python is only supported on Linux for Azure Functions.

Remove go worker entries from profiles where go is not in supportedRuntimes
(linux-premium, windows-consumption, windows-dedicated, linux-consumption).
Go is only supported on the Flex Consumption plan.

Fixes #5293

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3bb763e6-d45c-4b66-b044-67858ad44d49
@satvu
sarah (satvu) requested a review from a team as a code owner August 4, 2026 18:05
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3bb763e6-d45c-4b66-b044-67858ad44d49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Removes unsupported runtime entries from built-in hosting profiles so the v5 CLI’s profile-based validation aligns more closely with Azure production support constraints (notably Python on Windows, and Go outside Flex Consumption).

Changes:

  • Update built-in profiles to remove python from Windows profiles’ supportedRuntimes and workers.
  • Remove go from the workers constraints on non-Flex profiles.
  • Document the change in v5 release notes.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/Func/Profiles/BuiltInProfiles.json Removes Python from Windows profile runtime/worker lists and removes Go worker constraints from non-Flex profiles.
src/Func/release_notes.md Adds a release note entry describing the built-in profile updates.
Suppressed comments (1)

src/Func/Profiles/BuiltInProfiles.json:96

  • Same as windows-consumption: removing python from the workers map makes the worker version range unconstrained. A Python project on this profile can still trigger an automatic install of the python worker workload and only then fail the supportedRuntimes check, which is a surprising side effect for an unsupported runtime. Consider blocking auto-install earlier when the active profile does not support the detected runtime.
      "workers": {
        "node": {
          "version": "[3.13.0]"
        }
      },

Comment thread src/Func/Profiles/BuiltInProfiles.json
Comment thread src/Func/release_notes.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

test/Func.Tests/Commands/StartInitializationTests.cs:537

  • This assertion is order-dependent (it requires the supported runtime list to stay in exactly this sequence). Since profile runtime ordering is not semantically important, the test will become brittle if the list order changes in JSON/fixtures.
        ex.Message.Should().Contain("node, java, powershell, dotnet-isolated, custom");

ValidateSupportedRuntime now checks both project.StackName and
worker.WorkerRuntime (or workerId for pre-install) against the profile's
supportedRuntimes. A match on either is sufficient. This handles stacks
where the names differ:
  - Go: StackName='go', WorkerRuntime='native'
  - DotNet: StackName='dotnet', WorkerRuntime='dotnet-isolated'

Built-in profiles now use 'dotnet' (matching StackName) instead of
'dotnet-isolated' in supportedRuntimes.

The check runs in two places:
  1. Before auto-install: uses StackName + workerId to prevent unnecessary
     downloads for unsupported runtimes
  2. After resolution: uses StackName + WorkerRuntime for the definitive
     check once the worker is resolved

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3bb763e6-d45c-4b66-b044-67858ad44d49
Comment thread src/Func/Profiles/BuiltInProfiles.json Outdated
Comment thread test/Func.Tests/Commands/StartInitializationTests.cs
Comment thread test/Func.Tests/Commands/StartInitializationTests.cs Outdated
…ry constructor

- Revert supportedRuntimes back to 'dotnet-isolated' in all profiles to
  avoid breaking SetupRunner.DotNetProfileRuntime which is hardcoded to
  compare against this value.
- Rename ValidateSupportedRuntime parameter from 'workerRuntimeName' to
  'runtimeIdentifier' to clarify it accepts either a workload id or a
  worker runtime name depending on the call site.
- Add inline comment at pre-install call site explaining workerId.Value
  is the workload identifier, not the worker runtime name.
- Convert TestFunctionsProject to use primary constructor.
- Update test assertion to match reverted profile data.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3bb763e6-d45c-4b66-b044-67858ad44d49
@satvu
sarah (satvu) requested review from Ahmed Muhsin (ahmedmuhsin) and a lite review from Copilot August 6, 2026 16:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@satvu
sarah (satvu) requested a lite review from Copilot August 6, 2026 16:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/Func/Commands/Start/Initialization/Steps/ResolveFunctionsWorkerInitializationStep.cs:233

  • This error no longer includes what was actually detected (stackName and/or runtimeIdentifier). When debugging mismatches (especially where stack name differs from worker runtime), it’s useful to include both identifiers in the message, e.g. include stackName and runtimeIdentifier alongside stackDisplayName so users can see exactly what value failed validation.
        string message = $"Profile '{profile.Name}' does not support the '{stackDisplayName}' stack. "
            + $"Supported runtimes: {string.Join(", ", supportedRuntimes)}.";
        throw new GracefulException(message, isUserError: true);

src/Func/Commands/Start/Initialization/Steps/ResolveFunctionsWorkerInitializationStep.cs:212

  • The example "Go stack = \"go\" but worker runtime = \"native\"" should be verified against the actual worker runtime identifiers used by this CLI/host. If the Go worker runtime is not literally "native" in this codebase, this comment will mislead future maintainers; consider updating the example to a known-accurate mapping (or rephrasing to avoid hard-coding a potentially changing identifier).
    /// <summary>
    /// Checks whether the profile supports the runtime by matching against both the stack name
    /// and the runtime identifier (workload id or worker runtime name). Some stacks differ between
    /// the two (e.g. Go stack = "go" but worker runtime = "native"; DotNet stack = "dotnet" but
    /// worker runtime = "dotnet-isolated"). A match on either is sufficient.
    /// </summary>

src/Func/Commands/Start/Initialization/Steps/ResolveFunctionsWorkerInitializationStep.cs:226

  • This performs up to 2 ordinal-ignore-case comparisons per element of supportedRuntimes. Since you’re checking membership for exactly two values (stackName and runtimeIdentifier), consider materializing supportedRuntimes into a case-insensitive set (or using an existing case-insensitive lookup if available) and calling Contains for each value. This is simpler to read and avoids repeated comparisons on the startup path.
        if (supportedRuntimes.Any(runtime =>
            string.Equals(runtime, stackName, StringComparison.OrdinalIgnoreCase)
            || string.Equals(runtime, runtimeIdentifier, StringComparison.OrdinalIgnoreCase)))

@satvu

Copy link
Copy Markdown
Member Author

Copilot resolve the merge conflicts in this pull request

…-profiles

# Conflicts:
#	src/Func/Commands/Start/Initialization/Steps/ResolveFunctionsWorkerInitializationStep.cs

Co-authored-by: satvu <35204912+satvu@users.noreply.github.com>

Copilot AI commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Copilot resolve the merge conflicts in this pull request

Resolved. Merged vnext into this branch (commit 3cdb574). The only conflict was in ResolveFunctionsWorkerInitializationStep.cs, where I kept both the pre-install supported-runtime check from this branch and the new Log.ResolutionFailedAttemptingInstall call from vnext. Verified the BuiltInProfiles.json/release_notes.md diffs from this PR and the test changes in StartInitializationTests.cs came through intact.

Use the worker reference's expected runtime identity during pre-install profile validation so Go's native runtime alias is honored consistently.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3bb763e6-d45c-4b66-b044-67858ad44d49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Auto-installed Go workers may retain the incorrect go runtime identity, and test coverage gaps remain.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (2)

src/Func/Profiles/BuiltInProfiles.json:80

  • The bundled-profile test only checks the profile names and status, so these worker/runtime removals can regress without a failing test. Add assertions for both Windows profiles' supported runtimes/workers and for the absence of Go workers from the non-Flex profiles.
      "supportedRuntimes": [
        "node",
        "java",
        "powershell",
        "dotnet-isolated",
        "custom"

test/Func.Tests/Commands/StartInitializationTests.cs:597

  • This assertion covers the host IWorkloadInstaller, not the IFunctionsWorkerInstaller that performs worker auto-install. CreateRunner supplies a default worker-installer substitute, so the test can still pass if InstallAsync is called; wire in a named worker-installer substitute and assert that it receives no install call.
        await workloadInstaller.DidNotReceive().InstallFromCatalogAsync(
            Arg.Any<string>(),
            Arg.Any<NuGetVersion?>(),
            Arg.Any<string?>(),
            Arg.Any<bool?>(),
            Arg.Any<bool>(),
            Arg.Any<bool>(),
            Arg.Any<IProgress<WorkloadInstallProgress>?>(),
            Arg.Any<CancellationToken>());
  • Files reviewed: 6/6 changed files
  • Comments generated: 1
  • Review effort level: Lite

Apply the project worker reference runtime to newly installed workers so first-run Go projects start with FUNCTIONS_WORKER_RUNTIME=native.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 3bb763e6-d45c-4b66-b044-67858ad44d49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Unresolved review findings require additional profile and startup test coverage corrections.

Review details

Suppressed comments (3)

Previously missed (2) — in code that hasn't changed since the last review.

src/Func/Profiles/BuiltInProfiles.json:80

  • The bundled profile edits are not asserted by a test that loads the real registry: BuiltInProfileSourceTests checks only profile names/status, while the new start tests construct supportedRuntimes manually. Add assertions for the actual Windows and Linux definitions (including the removed Python/Go workers) so these production profile values cannot regress unnoticed.
      "supportedRuntimes": [
        "node",
        "java",
        "powershell",
        "dotnet-isolated",
        "custom"

test/Func.Tests/Commands/StartInitializationTests.cs:577

  • This test does not enter the worker auto-install path: CreateRunner defaults its worker resolver to return a resolved worker, and the DidNotReceive assertion targets the host IWorkloadInstaller, which is already bypassed by the installed host result. Configure the worker resolver to return NotInstalled, inject a worker-installer substitute, and assert that its InstallAsync was not called.

test/Func.Tests/Commands/StartInitializationTests.cs:481

  • Using ["native"] makes both the pre-install runtime and the post-install adjusted runtime match this test profile, so it never exercises the stack-name fallback that the real Flex profile needs (go stack vs native worker runtime). Use the actual supported value go here so a regression in the stackName comparison is caught.
            CreateResolvedProfile(workerRanges, ["native"]),
  • Files reviewed: 6/6 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

A moderate validation gap and two requested test-coverage improvements remain.

Review details

Suppressed comments (3)

src/Func/Commands/Start/Initialization/Steps/ResolveFunctionsWorkerInitializationStep.cs:53

  • This check only runs for NotInstalled and MissingCompatibleVersion failures. If an unsupported project resolves to InvalidInstallation (for example, an installed worker is missing worker.config.json, which the resolver reports as a non-installable failure), execution skips this validation and reports the worker error instead of enforcing the profile's supportedRuntimes. Run the project/reference check before ResolveWorkerAsync (while retaining the post-resolution check for the actual worker runtime).
            ValidateSupportedRuntime(context, project.StackName, project.WorkerReference.WorkerRuntime, project.StackDisplayName);

src/Func/Profiles/BuiltInProfiles.json:80

  • The new start tests exercise hand-built ResolvedProfile instances, while BuiltInProfileSourceTests only checks profile names and status. Please add a regression assertion for the bundled profiles' workers and supportedRuntimes entries; otherwise the removed Windows Python/Go support could be reintroduced in BuiltInProfiles.json without any test failing.
        "node",
        "java",
        "powershell",
        "dotnet-isolated",
        "custom"

test/Func.Tests/Commands/StartInitializationTests.cs:577

  • This test does not exercise the new pre-install guard: CreateRunner defaults to CreateWorkerResolverFactory(), whose resolver returns a resolved worker, so the TryGetInstallableWorker branch and workerInstaller.InstallAsync are never reached. Configure the resolver to return a NotInstalled result and assert the injected worker installer receives no InstallAsync call; otherwise a regression that validates only after auto-install would still pass.
        var runner = CreateRunner(projectResolver, new ProfileResolution.Resolved(profile, []), hostWorkloadResolver, workloadInstaller: workloadInstaller);
  • Files reviewed: 6/6 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Cover missing and invalid worker rejection, bundled runtime support, and both Go stack/runtime matches.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3bb763e6-d45c-4b66-b044-67858ad44d49
@satvu

Copy link
Copy Markdown
Member Author

Addressed the suppressed findings from the latest Copilot review in c046ede:

  • Validate the project stack/reference runtime before calling the worker resolver, retaining the post-resolution check. Unsupported profiles now take precedence over missing or invalid worker installations.
  • Correct the rejection test to configure NotInstalled/InvalidInstallation results and assert that neither the worker resolver nor IFunctionsWorkerInstaller.InstallAsync is called.
  • Load the actual bundled registry and assert supportedRuntimes and worker keys for all five profiles, including Python only on Linux, Go only on Flex, and dotnet-isolated retained.
  • Cover both go and native profile values for first-run Go installation, verifying normalization from the installer runtime go to native while preserving worker metadata.
  • Update release notes to describe the user-facing rejection before worker resolution/installation.

Validation: 47 targeted tests passed; strict Release build completed with zero warnings/errors.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The reviewed changes are covered by tests and align profiles with supported runtimes.

Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@satvu sarah (satvu) changed the title Remove unsupported runtimes from Windows built-in profiles Remove unsupported runtimes from SKU built-in profiles Sep 16, 2026
@satvu
sarah (satvu) merged commit 31e0df3 into vnext Sep 17, 2026
7 checks passed
@satvu
sarah (satvu) deleted the satvu/update-builtin-profiles branch September 17, 2026 18:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants