1

I am currently working my way into GitHub Actions as well as NUKE.build. My project consists of 2 jobs in GitHub Actions: The first job is responsible for reading the build configurations from a given .csproj file and setting it as a JSON array variable. The second job (which is spread across multiple runners) is then supposed to use this JSON array as the value for the matrix, executing my targets in NUKE, with the respective value as a parameter.

I have managed this so far with the following workflow (shortened):

name: Build Workflow
on:
  ...

jobs:
  get-configurations:
    runs-on: windows-latest

    outputs:
      configurations: ${{ steps.generate-matrix.outputs.configurations }}

    steps:
      ...

      - name: Get Build Configurations
        id: generate-matrix
        run: |
          dotnet NukeComponents --root . --relative-project-file-path "PathToProjectFile" --dotnet --get-configurations

  build:
    needs: get-configurations
    runs-on: windows-latest

    strategy:
      matrix:
        configuration: ${{ fromJson(needs.get-configurations.outputs.configurations) }}

    steps:
      ...
      - name: Build and test
        run: |
          $configuration = "${{ matrix.configuration }}"
          dotnet NukeComponents --root . --relative-project-file-path "PathToProjectFile" --configuration "$configuration"

And in my NUKE "GetConfigurations" target I have the following to set the variable:

var output = string.Join(',', configurations.Select(x => $"\"{x}\""));
Console.WriteLine($"::set-output name=configurations::[{output}]");

As I said, this also works so far. But now it is the case that "::set-output" is deprecated and should not be used anymore. It was said that you should use the following instead:

echo 'KEY=VALUE' >> $GITHUB_OUTPUT

I have tested this and it also works when I define it directly in the workflow:

  - name: Set configurations
    id: set-configurations
    run: echo 'configurations=["20200-Release","20201-Release","20202-Release"]' >> "$env:GITHUB_OUTPUT"

  - name: echo output of previous step for testing
    run: echo ${{ steps.set-configurations.outputs.configurations }}

However, if I now go and try to adjust the line in my NUKE target:

var output = string.Join(',', configurations.Select(x => $"\"{x}\""));
Console.WriteLine($"echo 'configurations=[{output}]' >> '$env:GITHUB_OUTPUT'");

And the workflow file:

- name: Get Build Configurations
  id: generate-matrix
  run: |
    dotnet NukeComponents --root . --relative-project-file-path "PathToProjectFile" --dotnet --get-configurations

 - name: echo output of previous step for testing
   run: echo ${{ steps.generate-matrix.outputs.configurations }}

Then apparently I have the problem that "configurations" remains empty (Get as error message that InputObject in echo command is empty).

I have also tried things like setting the configurations as an environment variable in the NUKE target.

But I can't get it to work. It looks like the echo command is not executed, but just output. But maybe I am wrong and the error is somewhere else.

Can someone help me here?

CaptTaifun
  • 321
  • 5
  • 15
  • Did you try converting those single quotes to escaped double quotes? – Azeem Jul 19 '23 at 04:36
  • Not really sure what you're doing. If that escaped double quotes do not work then you may probably need to run `echo` as a command i.e. https://stackoverflow.com/questions/13738168/run-command-line-code-programmatically-using-c-sharp. – Azeem Jul 19 '23 at 04:39
  • 1
    Unfortunately both did not work, the variables in the actions workflow remain empty. Regarding the new process: I guess that the command must be executed in the same process in which the GitHub Actions step is running, but that's just a wild theory. I will now remove NUKE from the equation and just use a console program where I just issue the echo command to set the variable. Let's see if that does anything. – CaptTaifun Jul 19 '23 at 10:55
  • 1
    Ok, so running it in another process seems to work after all. However, I had to modify it a bit: In ProcessStartInfo I define the powershell.exe as filename and RedirectStandardOutput = true. I also had to modify the command itself (had to add more quotes and backslashes). The command I now run in a separate powershell: ExecuteCommand($"echo 'configurations=\"[\\"20200-Release\\",\\"20201-Release\\",\\"20202-Release\\"]\"' >> $env:GITHUB_OUTPUT"); In the next job use it as: needs.get-configurations.outputs.configurations Do you want to write a response so I accept this? – CaptTaifun Jul 19 '23 at 13:00
  • Good to hear that. Yes, given those outer quotes, inner nested quotes need to be escaped. You may self-answer this with all the details and examples. Thanks! – Azeem Jul 19 '23 at 13:43

1 Answers1

1

Thanks to @Azeem's help, I was able to solve the problem.

My answer is probably not 100% accurate, however the solution works for me and so I am posting it here. If anyone finds an error in my answer, feel free to correct it!

I removed NUKE from the equation and used a simple console application written in .NET 7.

I think my guess about GitHub Runner not interpreting the output of my console program and executing commands present in it seems to be correct. In the console program, I ran the following command in the console:

Console.WriteLine("echo 'configurations=\"[\\\"20200-Release\\\",\\\"20201-Release\\\",\\\"20202-Release\\\"]\"' >> $env:GITHUB_OUTPUT");

However, it seems that the GitHub runner does not execute the echo command, but simply returns it as output, which probably makes sense.

So what I needed to do is run the echo command in a separate PowerShell:

    static void Main(string[] args)
    {
        ExecuteCommand($"echo 'configurations=\"[\\\"20200-Release\\\",\\\"20201-Release\\\",\\\"20202-Release\\\"]\"' >> $env:GITHUB_OUTPUT");
    }


    private static void ExecuteCommand(string command)
    {
        var processInfo = new ProcessStartInfo
        {
            FileName = "C:\Windows\System32\\WindowsPowerShell\v1.0\\powershell.exe",
            Arguments = $"/c {command}",
            UseShellExecute = false,
            RedirectStandardOutput = true,
            CreateNoWindow = true
        };


        Process.Start(processInfo);
    }

The additional "\" in, for example. \\\"20201-Release\\\", are necessary because the array is in quotes and the whole thing, in this case, is interpreted by PowerShell.

The GitHub workflow job looks like this:

jobs:
  get-configurations:
    runs-on: windows-latest

    outputs:
      configurations: ${{ steps.generate-matrix.outputs.configurations }}

    steps:
      ...

      - name: Get Build Configurations
        id: generate-matrix
        run: ./NukeComponents/GetConfigurations.exe

      - name: echo env of previous step for testing
        run: echo ${{ steps.generate-matrix.outputs.configurations }}
CaptTaifun
  • 321
  • 5
  • 15