Skip to content

feat: allow for envfile path as a list #54

Merged
dnitsch merged 11 commits intomainfrom
fix/envfile-pipeline-task
Sep 22, 2025
Merged

feat: allow for envfile path as a list #54
dnitsch merged 11 commits intomainfrom
fix/envfile-pipeline-task

Conversation

@dnitsch
Copy link
Copy Markdown
Collaborator

@dnitsch dnitsch commented Sep 18, 2025

SUMMARY:

Allow for specification of multiple paths on the envfile property.

Provides recursive merging of envfile properties and path appending for cascading inheritance.

Taking the below example definition eirctl.yaml

contexts:
  withenv:
    envfile:
      path: local/envfile/one.env
      
tasks:
  one: 
    context: withenv
    command: 
      - |
        echo "task one SET_IN_PIPELINE: $SET_IN_PIPELINE"
    envfile:
      path:
        - local/envfile/one.env
  two: 
    command: 
      - | 
        echo "task two SET_IN_PIPELINE: $SET_IN_PIPELINE"
pipelines:
  p1: 
    - task: one
      envfile:
        path:
          - local/envfile/two.env
    - task: two
      env: 
        SET_IN_PIPELINE: bar
      envfile:
        path:
          - local/envfile/one.env
  p2: 
    - pipeline: p1
      envfile:
        path:
          - local/envfile/p2.env

each of the referenced envfiles are merged with the last (or top most specified wins)

if each file contains SET_IN_PIPELINE variable set at a different value -> eirctl run p2

you will get

task two SET_IN_PIPELINE: bar -> as env: {} will directly set will always take highest precedence
task one SET_IN_PIPELINE: p2-override -> the top most specified envfile path will set the value i.e. overwrite any previously set value for the same key in the previous envfiles

if multiple keys are specified that do not clash they will be merged together -> in the specific example for task one, you would end up with this list
envfile.path: ["local/envfile/one.env", "local/envfile/two.env", "local/envfile/p2.env"]
it gets processed in order from left to right

fix: ensure backwards compatibility
@dnitsch dnitsch changed the title fix: allow for envfile path as array feat: allow for envfile path as a list Sep 19, 2025
docs: update docs around envfile and merging precedence
@dnitsch
Copy link
Copy Markdown
Collaborator Author

dnitsch commented Sep 19, 2025

/build-debug

@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds support for specifying multiple envfile paths as a list, providing cascading inheritance and recursive merging of environment variables. The primary change converts envfile.path from a single string to accept either a string or an array of strings.

  • Updated envfile path handling to support lists with proper merging order
  • Enhanced test coverage for envfile path precedence and merging behavior
  • Upgraded Go version and container images to latest versions

Reviewed Changes

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

Show a summary per file
File Description
internal/utils/utils.go Modified PathValue type to support string slice and updated path handling methods
scheduler/stage.go Added envfile field to Stage struct with getter/setter methods and merging logic
scheduler/denormalize.go Implemented envfileMerge function for proper cascading of envfile paths
schemas/schema_v1.json Updated JSON schema to support both string and array types for envfile path
variables/variables.go Updated constructor calls to use NewVariables() instead of struct literals
Multiple test files Enhanced test coverage for envfile path precedence and merging scenarios

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

// since we want to search for a partial match. this loop is required
for _, verbotenPair := range forbiddenContainerArgsPairs {
slices.ContainsFunc(cargs, func(s string) bool {
_ = slices.ContainsFunc(cargs, func(s string) bool {
Copy link

Copilot AI Sep 22, 2025

Choose a reason for hiding this comment

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

The result of slices.ContainsFunc is being discarded with _. If the function call has side effects or the result is needed for logic, this should be handled properly.

Copilot uses AI. Check for mistakes.
Comment thread runner/runner.go
}


//
Copy link

Copilot AI Sep 22, 2025

Choose a reason for hiding this comment

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

Empty comment should be removed or completed with meaningful content.

Suggested change
//

Copilot uses AI. Check for mistakes.
@dnitsch dnitsch merged commit 4614dfb into main Sep 22, 2025
9 checks passed
@dnitsch dnitsch deleted the fix/envfile-pipeline-task branch September 22, 2025 08:58
runs-on: ubuntu-24.04
container:
image: golang:1.24.4-bookworm
image: public.ecr.aws/docker/library/golang:1-trixie
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.

More of a heads up than a review as I don't think you are using it directly, but pwsh is currently not trivially installable on Debian 13 (Trixie) due to the fact that it's missing libicu =< 74 as it only ships with libicu76:

  • it's possible to install framework dependant versions of pwsh, but they are 3rd party, not Microsoft; you also need to use .NET 10.
  • you can also install libicu74 manually using dpkg, by downloading it from the bookworm repo.
  • my PR that fixes it was merged two weeks ago but hasn't actually made it into the release channel, based upon comments from the Microsoft team it may not do so until .NET 10 is released as they are only targeting libicu76 support from .NET 10 onwards.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This was kind of thought about in a slightly different way and that was to actually create containers with eirctl in it in different flavours one of those would be the sdk8|910 container which just has the binary copied into it. this would give people the ability to leverage an eirct container with a correct shell already.

The only application for this sort of a flow though is when you are defining a runner image e.g. in gitlab or bitbucket where you want to perform some commands in a pwsh before you execute an eirctl pipeline|task.

The other way around you would ideally define a context of microsoft/sdk:8|9|10 which ships with pwsh 7+ and your eirctl task run the commands in pwsh containers already.

Hope that makes sense @RichardSlater but, DM me or reply here, if I missed the point of anything you are trying to say.

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.

That makes sense, as I say it was a heads up that if any PowerShell was needed there is a lack of support from Microsoft for Debian 13.

}

taskRunner := TestTaskRunner{}
taskRunner := mockTaskRunner{
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.

There is a lot of repetition here with L103, L149, L181, L225, L269 - could these be refactored into a single common function?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

yeah possibly with a t.Helper() signifier - though as they are tests it's OK for them to be a bit wet, there are slight differences between some of them in what they assert and test inside

- task: golint
- task: vuln:check
# govet is run as part of golint
# - task: govet No newline at end of file
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.

New line please :)

Comment thread README.md
- `task` - task to execute on this stage
- `pipeline` - pipeline to execute on this stage
- `env` - environment variables. All existing environment variables will be passed automatically
- `envfile` - envfile specifications allow you to to leverage a cascade of envfile paths and rules.Tthese get merged with any envfiles specified on the task level.
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.

Suggest defining the order of precedence here too:

  • an envfile specified with a higher index in the array, i.e. after another, will take precedence over another.
  • an envfile specified at the task level will take precedence over another specified at the pipeline level.

Additionally 216s/Tthese/ These/g and 216s/ / /g.

@RichardSlater
Copy link
Copy Markdown
Contributor

I was clearly too slow :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants