5

I'm trying to make a GitHub Actions workflow where one job has a dynamic value to its environment setting. https://docs.github.com/en/actions/reference/environments I have two jobs in this workflow. The first job determines which environment the second job will run in, and this is in turn based on which git branch the Actions job is run from.

This is my naive attempt to make it work, but I get an error which says

(Line: 29, Col: 18): Unrecognized named-value: 'needs'. Located at position 1 within expression: needs.get-environment.outputs.environment_name

name: Environments

on:
  push:
  workflow_dispatch:

jobs:
  get-environment:
    runs-on: ubuntu-latest
    outputs:
      environment_name: ${{ steps.get_environment.outputs.environment_name }}
    steps:
      - id: get_environment
        run: |
          if [ "$GITHUB_REF" = "refs/heads/test" ]
          then
            echo "::set-output name=environment_name::test"
          elif [ "$GITHUB_REF" = "refs/heads/qa" ]
          then
            echo "::set-output name=environment_name::qa"
          elif [ "$GITHUB_REF" = "refs/heads/master" ]
          then
            echo "::set-output name=environment_name::production"
          fi
    
  use-environment:
    runs-on: ubuntu-latest
    needs: [get-environment]
    environment: ${{ needs.get-environment.outputs.environment_name }}
    steps:
      - uses: actions/checkout@v2

      - name: Run a one-line script
        run: echo ${{ secrets.ENV_DEPENDENT_SECRET }}

Is it possible to achieve what I'm trying to do? My end goal is to have a single workflow file for three different app environments (test, QA and prod), where each app environment uses a separate Actions environment. (terminology gets confusing, I know)

Magnus
  • 589
  • 8
  • 26
  • 1
    Looks like there's an issue raised on the repo for this as well: https://github.com/actions/runner/issues/998 – Jim Jimson Mar 28 '21 at 10:20

4 Answers4

0

Have you tried

>   use-environment:
>     runs-on: ubuntu-latest
>     needs: [get-environment]
>     environment: 
>          name: ${{ needs.get-environment.outputs.environment_name }}
0

I actually had to solve this issue for the place I work. You can use a matrix with the list of your env names and dynamically set the environment name. Take a look at the link for the workflow file.

enter image description here

tomerpacific
  • 4,704
  • 13
  • 34
  • 52
Michael
  • 54
  • 3
  • Could you expand on this more? How do I use this to actually pick and environment? It seems this would just run the code 4 times, once for each environment – Justin Ohms Nov 21 '22 at 05:31
  • @JustinOhms yes that would be the objective, in github it has a section for environment specific secrets and you just name the secret the same thing. Settings -> Environments -> Click environment name -> Environment secrets – Michael Nov 22 '22 at 06:10
  • Thanks for confirming @Michael that it does exactly what I thought it would do. My confusion comes from the fact that I don't think this actually answers the OPs original question. While the OP wants to use environments I don't think they want to have one push trigger deployments using all those environments. – Justin Ohms Nov 22 '22 at 16:22
0

I did something very similar to dynamically set the environment context.

  ##################
  # Set Deploy Env #
  ##################
  SetDeployEnv:
    name: 'Set Deployment Environment'
    runs-on: [self-hosted, linux]
    outputs:
      deploy_env: ${{ steps.get_env.outputs.deploy_env }}
      
    steps:
    - name: Determine Environment
      id: get_env
      run: |
          if [[ ${{ github.ref }} =~ /^refs\/heads\/sprint+[_|-]+[0-9]*+[_|-]+\S*/gi ]]; then
              echo "::set-output name=deploy_env::Test"
          elif [[ ${{ github.ref }} =~ /^refs\/heads\/sprint+[_|-]+[0-9]*/gi ]]; then
              echo "::set-output name=deploy_env::PreProd"
          elif [[ ${{ github.ref }} =~ /^refs\/heads\/main|master/gi ]]; then
              echo "::set-output name=deploy_env::Prod"
          else
              echo "::set-output name=deploy_env::Test"
          fi

Then do some like this for any subsequent jobs that need the environment context set.

  ################
  # Test Job     #
  ################
  TestJob:
    needs: SetDeployEnv
    name: 'Test Job'
    runs-on: [self-hosted, linux]
    environment: 
        name: ${{ needs.SetDeployEnv.outputs.deploy_env }}

    steps:
    - name: echo
      run: | 
        echo ${{ needs.SetDeployEnv.outputs.deploy_env }}
Frank The Tank
  • 441
  • 4
  • 6
0

Just to clarify one of the previous answers and why it works, you can put expressions like what you want in the environment, but you can only do it if you pass an object.

This is the shorthand format, and it doesn't support contexts and expressions:

    runs-on: ubuntu-latest
    needs: [get-environment]
    environment: ${{ needs.get-environment.outputs.environment_name }} # fails

This is the "true format", and it does support contexts and expressions:

    runs-on: ubuntu-latest
    needs: [get-environment]
    environment:
      name: ${{ needs.get-environment.outputs.environment_name }} # works!
      # You didn't ask for this, but it also accepts 
      # url: ${{ needs.get-environment.outputs.environment_url }}

Source: Github Issues comment

Dan Crews
  • 3,067
  • 17
  • 20