How to have input options be key/value pairs in github actions - github-actions

I have 3 servers that are options of an input server_name but I want the the user sellecting the options to only see server names like server_1, server_2 & server_3 but server 1-3 should have values like instance IDs. Here's the code:
name: test
on:
workflow_dispatch:
inputs:
server_name:
description: The server where you wish to deploy & test your code.
required: true
type: choice
options:
- server_1: i-xxxxxxxxxxxxxxxxx
- server_2: i-xxxxxxxxxxxxxxxxx
- server_3: i-xxxxxxxxxxxxxxxxx
IDK if my syntax here server_1: i-xxxxxxxxxxxxxxxxx is correct & I have not seen any examples of this.
perhaps I need to create some additional logic to get this to work?

You can configure and access these values as environment variables like in the following example:
name: test
on:
workflow_dispatch:
inputs:
server_name:
description: The server where you wish to deploy & test your code.
required: true
type: choice
options:
- server_1
- server_2
- server_3
env:
server_1: "i-xxxxxxxxxxxxxxxxx"
server_2: "i-xxxxxxxxxxxxxxxxx"
server_3: "i-xxxxxxxxxxxxxxxxx"
jobs:
test:
runs-on: ubuntu-latest
steps:
- run: echo ${{ env[inputs.server_name] }}
To read more about env context, visit Contexts article

Related

How to separate conditions for different event types in GitHub Actions

We have a workflow file:
---
name: 'Deploy Test Env'
on:
pull_request:
types:
- edited
- opened
- synchronize
branches:
- develop
paths:
- '**.js'
jobs:
deploy:
# yamllint disable rule:line-length
name: '[DEV] DEPLOY'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout#v2
- name: Deploy
run: |
echo 'Deploy Dev Env by ${{ github.event.action }} event type' >> "${GITHUB_STEP_SUMMARY}"
When new Pull Request (feature_branch → develop) is created or new commit inside feature_branch is occured, pull_request's opened (or synchronize) event is triggering Job.
Here is a paths condition: if none of JavaScript files are changed, application source code is the same and we don't need to deploy new test environment. That is correct.
But, here is third action type: edited. It is used because we have environment parameters passed inside Pull Request message. And if message is changed (edited), it means that parameters possibly changed too, and we have to re-deploy test environment even if **.js files are not changed. But because of paths condition edited event will not be triggered too.
In other words, description should be looks like:
---
name: 'Deploy Test Env'
on:
# will be triggered only if *.js files changed
pull_request:
types:
- opened
- synchronize
branches:
- develop
paths:
- '**.js'
# will be triggered anytime when PR contents are updated
pull_request:
types:
- edited
branches:
- develop
But YAML doesn't support duplicated keys and this format is wrong.
OR:
on:
pull_request:
types:
# paths are set only for `opened` and `synchronize` types
- type: edited
- type: opened
paths:
- '**.js'
- type: synchronize
paths:
- '**.js'
branches:
- develop
But types should be a list...
The question is: Is it possible to describe desired behavior? Maybe pull_request may be passed twice as array or paths may be set under the edited type (something like my second example)
You can use reusable workflows to achieve this.
Divide your workflow into three (3) workflows:
ci.yml: reusable workflow (workflow that performs stuff)
ci-pr-opened-synchronize.yml: reusable workflow caller (for PR opened/synchronize for .js files)
ci-pr-edited.yml: reusable workflow caller (for PR edited)
The above reusable workflow callers will call the ci.yml workflow.
Here's a complete working example with .md files filter and PRs to the main branch (https://github.com/iamazeem/github-actions-reusable-workflow-test):
ci.yml
name: CI
on:
workflow_call:
inputs:
message:
type: string
description: custom message
required: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Print message
if: ${{ inputs.message }}
env:
MESSAGE: ${{ inputs.message }}
run: |
echo "message: $MESSAGE"
ci-pr-opened-synchronize.yml
name: PR opened/synchronize
on:
pull_request:
types:
- opened
- synchronize
branches:
- main
paths:
- '**.md'
jobs:
pr-open-sync:
uses: ./.github/workflows/ci.yml
with:
message: 'PR opened/synchronized'
ci-pr-edited.yml
name: PR edited
on:
pull_request:
types:
- edited
branches:
- main
jobs:
pr-edited:
uses: ./.github/workflows/ci.yml
with:
message: 'PR edited'
You may check this PR and its respective actions for this sample:
PR: https://github.com/iamazeem/github-actions-reusable-workflow-test/pull/1
Actions: https://github.com/iamazeem/github-actions-reusable-workflow-test/actions
Here is one more example of reusable workflows:
.github/workflows/reuser_on_edited.yml
the workflow will reuse to_reuse.yml jobs when PR contents are edited
---
name: 'Reuser on Edited'
on:
pull_request:
types:
- edited
branches:
- 'develop'
jobs:
reuse:
uses: ./.github/workflows/to_reuse.yml
with:
original_github: ${{ toJSON(github) }}
other_input: 'BOOM! edited'
.github/workflows/reuser_on_pr_changed.yml
the workflow will reuse to_reuse.yml jobs when some of **.js files is changed.
---
name: 'Reuser on PR changed'
on:
pull_request:
types:
- opened
- synchronize
branches:
- 'develop'
paths:
- '**.js'
jobs:
reuse:
uses: ./.github/workflows/to_reuse.yml
with:
original_github: ${{ toJSON(github) }}
.github/workflows/to_reuse.yml
the file to reuse jobs inside it
on:
workflow_call:
inputs:
original_github:
type: string
required: true
description: "github context that passed from original workflow (JSON)"
other_input:
type: string
default: 'default'
required: false
description: "just for LOLs"
jobs:
deploy_job:
runs-on: ubuntu-latest
steps:
- name: Checkout v2
uses: actions/checkout#v2
with:
ref: ${{ fromJSON(inputs.original_github).event.pull_request.head.sha }}
- name: Deploy
run: |
{
echo 'Deploy Dev Env by `${{ fromJSON(inputs.original_github).event.action }}` event type';
echo '';
echo 'Also `${{ inputs.other_input }}` input is passed';
} >> "${GITHUB_STEP_SUMMARY}"
Original github context may be passed as JSON string and reused inside different workflow.
Also, different conditions (paths, etc.) may be set for different pull_request action types.

how to run Github Actions Jobs in parallel using matrix?

I've really struggled here doing this for the first time and having no background in development.
We have an action that checks the status of several services running on different envs (DEV, TEST, PROD) and sends notifications to Microsoft Teams Channel.
At the moment there is a dedicated action for each env and the goal is to combine them in one.
the action itself:
name: Services Health Check
on:
workflow_dispatch:
schedule:
- cron: '*/30 * * * *'
env:
DEV: https://app.dev.contoso.com
TEST: https://app.test.contoso.com
PROD: https://app.contoso.com
TEAMS_TOKEN_DEV: ${{ secrets.HEALTH_CHECK_TEAMS_WEB_HOOK_URL_DEV }}
TEAMS_TOKEN_TEST: ${{ secrets.HEALTH_CHECK_TEAMS_WEB_HOOK_URL_TEST }}
TEAMS_TOKEN_PROD: ${{ secrets.HEALTH_CHECK_TEAMS_WEB_HOOK_URL_PROD }}
jobs:
#here I want to create a matrix as a JSON array to look like this, but Im not sure if I do it right (I am also not sure if I correctly escape the characters and which one should I escape):
#[
# { dev : https://app.dev.contoso.com, webhook : ${{ secrets.WEB_HOOK_URL_DEV }} },
# {test : https://app.test.contoso.com, webhook : ${{ secrets.WEB_HOOK_URL_TEST }} },
# {prod : https://app.contoso.com, webhook : ${{ secrets.WEB_HOOK_URL_TEST }} }
#]
env-matrix:
name: Setup ENV Matrix
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.matrix.outputs.env }}
steps:
- id: matrix-env
run: |
echo '::set-output name=env::[\{\"env\"\:\"$DEV\", \"webhook\"\:\"$TEAMS_TOKEN_DEV\"\}, \{\"env\"\:\"$DEMO\", \"webhook\"\:\"$TEAMS_TOKEN_DEMO\"\}, \{\"env\"\:\"$TEST\", \"webhook\"\:\"$TEAMS_TOKEN_TEST\"\}, \{\"env\"\:\"$POC\", \"webhook\"\:\"$TEAMS_TOKEN_POC\"\}, \{\"env\"\:\"$PRE\", \"webhook\"\:\"$TEAMS_TOKEN_PRE\"\}, \{\"env\"\:\"$PROD\", \"webhook\"\:\"$TEAMS_TOKEN_PROD\"\}]'
#and the healthcheck job itself
healthcheck:
needs: env-matrix
name: Health Check
runs-on: ubuntu-18.04
strategy:
matrix:
value: ${{ fromJson(needs.env-matrix.outputs.matrix-env)}}
steps:
- name: service1
uses: repo/action
continue-on-error: true
with:
url: '${{ matrix.value.env }}/service1/q/health/ready'
teamsWebHookURL: '${{ matrix.value.webhook }}'
- name: service2
uses: repo/action
continue-on-error: true
with:
url: '${{ matrix.value.env }}/service2/q/health/ready'
teamsWebHookURL: '${{ matrix.value.webhook }}'
so the job must run on DEV with TEAMS_TOKEN_DEV, on TEST with TEAMS_TOKEN_TEST, but I don't know the way to access an array item, so the steps are incorrect.
Any help will be appreciated. If you know a simpler solution pls share.
Thanks for your time and help
Another way of rewriting your workflow is to define the name of the secrets in the matrix and then using Array notation to fetch the actual value of the secrets. Below is a way of doing this and it is not a clone of your workflow. But this should give you an idea.
name: Services Health Check
on:
workflow_dispatch:
jobs:
healthcheck:
name: Health Check
runs-on: ubuntu-18.04
strategy:
matrix:
environment: [dev, test, prod]
include:
- environment: dev
url: https://app.dev.contoso.com
webhook: HEALTH_CHECK_TEAMS_WEB_HOOK_URL_DEV
- environment: test
url: https://app.test.contoso.com
webhook: HEALTH_CHECK_TEAMS_WEB_HOOK_URL_TEST
- environment: prod
url: https://app.prod.contoso.com
webhook: HEALTH_CHECK_TEAMS_WEB_HOOK_URL_PROD
steps:
- name: test_1
run: |
echo ${{ format('{0}{1}', matrix.url, '/service1/q/health/ready') }}
echo ${{secrets[matrix.webhook]}}
- name: test_2
run: |
echo ${{ format('{0}{1}', matrix.url, '/service2/q/health/ready') }}
echo ${{secrets[matrix.webhook]}}

Having issues with variables and outputs

I started learning Github Actions a few days ago and I am playing around with it. I am having issues with defining outputs and using them in variables or as input values in another workflow step. I am not sure what I am doing wrong.
name: Demo
on:
workflow_dispatch:
jobs:
build:
runs-on: [ ubuntu-latest ]
outputs:
paths: ${{ steps.find_path.outputs.paths }}
steps:
- name: Code Checkout
uses: actions/checkout#v2
- name: Find Paths
id: find_path
run: |
all_paths=$(cat document.txt)
# some code
echo "::set-output name=paths::$(echo ${all_paths})"
- name: List
id: list_path
run: |
var_paths=${{ steps.find_path.outputs.paths }}
for part in ${var_paths[#]}; do
# parent_dir=$(cat...)
# ....
# some code
echo $part
done
I have a text file with some paths in it
/home/ubuntu
/home/ubuntu/docs
/home/ariel/code
I want to use the output from find_path step in another list_path step. There is some other code I didn't include as it's irrelevant to my question. So I defined the paths output in find_path step and it is basically a space-separated string /home/ubuntu /home/ubuntu/docs /home/ariel/code and that's format I want to have.
But I don't know how to use outputs from one step as input value in another step.
Basically,
var_paths=/home/ubuntu /home/ubuntu/docs /home/ariel/code
But when I loop var_paths I get weird errors like no such file or directory.
You're missing the quotes when assigning the output from the step to the variable:
name: Demo
on:
workflow_dispatch:
jobs:
build:
runs-on: [ ubuntu-latest ]
steps:
- name: Code Checkout
uses: actions/checkout#v3
- name: Find Paths
id: find_path
run: |
all_paths=$(cat document.txt)
# some code
echo "::set-output name=paths::$(echo ${all_paths})"
- name: List
id: list_path
run: |
# add quotes here
var_paths="${{ steps.find_path.outputs.paths }}"
for part in ${var_paths[#]}; do
# parent_dir=$(cat...)
# ....
# some code
echo $part
done
Misc comments:
You don't need to declare the outputs on the job level unless the output from a step should also be the output from the job. In your case, you're only using the output between steps.
The checkout action is available in v3

Can I define a global across jobs

I have a workflow with 2 jobs:
on: [push]
jobs:
ssql:
runs-on: ubuntu-latest
### bunch of steps in between ###
- name: Upload data as artifact
uses: actions/upload-artifact#v2
with:
name: ${{ env.GAME }} + "-" + "data"
path: output_data/training-data.csv
env:
GAME: "FunGame"
Rtrain:
runs-on: ubuntu-latest
name: Train model
needs: ssql
steps:
- name: checkout current repo
uses: actions/checkout#v2
- name: Retreive data from ssql job
uses: actions/download-artifact#v2
with:
name: ${{ env.GAME }} + "-" + "data"
env:
GAME: "FunGame"
I had to set env variable $GAME twice, once in each job. Is there any syntax where I can e.g. add this at the top to make it truly global across jobs, e.g. something like:
on: [push]
env:
GAME: "FunGame"
jobs: ...
You can set an env variable exactly as you described at the workflow level.
Just note that it can conflict with env variables set at the job level, or at the step level, if they have the same name. In that case, the variable used is the most specific one: STEP over JOB over WORKFLOW.
Reference 1 + Reference 2
Here is an example of how to use env variables at different levels (without conflict):
name: Environment Workflow
on:
workflow_dispatch:
env:
WORKFLOW_VARIABLE: WORKFLOW
jobs:
job1:
runs-on: ubuntu-latest
env:
JOB_VARIABLE: JOB
steps:
- name: Run Commands with various variables
if: ${{ env.WORKFLOW_VARIABLE == 'WORKFLOW' }}
env:
STEP_VARIABLE: STEP
run: |
echo "Hello World"
echo "This is the $WORKFLOW_VARIABLE environment variable"
echo "This is the $JOB_VARIABLE environment variable"
echo "This is the $STEP_VARIABLE environment variable"
Full workflow implementation (if you want to reproduce)
Previous workflow run display

using defined environmental variable in with block for github actions

I am trying to figure out how to reference a global scoped environmental variable for input in to an action like so:
name: validate
on: pull_request
env:
CONFIG_PATH: configuration/conf.json
jobs:
upload_config:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v1
- name: create config
shell: bash -l {0}
run: |
mkdir `dirname ${CONFIG_PATH}`
echo "some config" > ${CONFIG_PATH}
- name: upload config
uses: actions/upload-artifact#v1
with:
name: config
path: ${{ CONFIG_PATH }}
However I am getting an invalid yaml error stating there is an "Unrecognized named-value: 'CONFIG_PATH'". If I try referencing the environmental variable like so:
path: ${CONFIG_PATH}
I get a "Path does not exist ${CONFIG_PATH}" error.
Any ideas?
I couldn't find a clear example of it in the docs but you need to use the env context for this like so:
path: ${{ env.CONFIG_PATH }}