Skip to content

[GitHubActions] generator: emit a workflow-level env: block #385

Description

@avidenic

Description

Add support for emitting a workflow-level env: block in the generated YAML: variables defined once at the top of the workflow and inherited by every job and step.

GitHubActionsConfiguration.Write (src/Fallout.Common/CI/GitHubActions/Configuration/GitHubActionsConfiguration.cs:19-74) writes the workflow in a fixed order (name, on, permissions, concurrency, jobs) with no top-level env: block, and neither GitHubActionsConfiguration nor GitHubActionsAttribute exposes an env-map property. The only environment variables Fallout emits today are per-run-step and single-step-scoped, produced by GitHubActionsAttribute.GetImports() (GitHubActionsAttribute.cs:223-236) and written inline under the one dotnet fallout run step (GitHubActionsRunStep.cs). There is no way to declare a variable once and have it reach checkout/cache/artifact steps too (e.g. DOTNET_NOLOGO, DOTNET_CLI_TELEMETRY_OPTOUT, NUGET_XMLDOC_MODE, a shared Configuration).

Proposed change:

  1. Add a public string[] Env { get; set; } = []; property (entries in KEY: value form) to GitHubActionsAttribute. (We name it Env rather than our POC's EnvironmentalVariables to avoid confusion with the deployment environment: keyword.)
  2. Carry it through GetConfiguration into a matching property on GitHubActionsConfiguration.
  3. In Write, when non-empty, emit a top-level env: block (one indented KEY: value line per entry) after on: and before permissions:.
  4. Add a minimal assertion that each entry contains a colon, so a typo emits a build error rather than malformed YAML silently.

Scope is intentionally limited to the workflow-level env map. Job- and step-level env are out of scope; they only become meaningful once multi-job or matrix workflows exist.

Usage Example

[GitHubActions(
    "ci",
    GitHubActionsImage.UbuntuLatest,
    On = [GitHubActionsTrigger.Push, GitHubActionsTrigger.PullRequest],
    InvokedTargets = [nameof(Test)],
    Env =
    [
        "DOTNET_CLI_TELEMETRY_OPTOUT: 1",
        "DOTNET_NOLOGO: true",
        "NUGET_XMLDOC_MODE: skip",
        "Configuration: Release",
    ])]
public partial class Build : NukeBuild { /* ... */ }

Resulting YAML:

name: ci

on: [push, pull_request]

env:
  DOTNET_CLI_TELEMETRY_OPTOUT: 1
  DOTNET_NOLOGO: true
  NUGET_XMLDOC_MODE: skip
  Configuration: Release

jobs:
  ubuntu-latest:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - name: 'Run: Test'
        run: ./build.cmd Test

Alternative

There is no workflow-wide alternative today. To approximate a shared variable you'd re-declare it on every step that needs it, and it still can't reach non-run steps. The remaining workaround is hand-editing the generated YAML, which the generator overwrites on the next regeneration.

Could you help with a pull-request?

Yes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions