Condititionally set Environmental Variable in GitHub Actions Workflows [duplicate] - github

I currently have two GitHub actions workflow files that are pretty much identical, only one is configured to react to push/pull_requests on branch master the other on production.
The staging workflow starts like this:
env:
GCLOUD_PROJECT: my-project-stg
VERCEL_TARGET: staging
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
The production workflow starts like:
env:
GCLOUD_PROJECT: my-project-prd
VERCEL_TARGET: production
on:
push:
branches: [ production ]
pull_request:
branches: [ production ]
The rest of the workflow files is the same, so this is clearly not very DRY.
I would like to have 1 single workflow file and somehow switch between two sets of variables based on the branch name. Is there a way to achieve this or am I maybe approach this from the wrong angle?
If it were possible to extend both workflow files on a shared base definition that would also solve it I guess.

It is not possible to set workflow-level environment variables from a job. Each job runs in its own machine and setting an env variable there only affects all of the later steps in that job.
There are currently two ways to share data between jobs; either you create an artifact and use that, or you declare and set job outputs. The latter works for string values.
Here's an example:
name: "Main"
on:
push:
branches:
- master
- production
pull_request:
branches:
- master
- production
jobs:
init:
runs-on: ubuntu-latest
outputs:
gcloud_project: ${{ steps.setvars.outputs.gcloud_project }}
phase: ${{ steps.setvars.outputs.phase }}
steps:
- name: Cancel previous workflow
uses: styfle/cancel-workflow-action#0.4.0
with:
access_token: ${{ github.token }}
- name: Set variables
id: setvars
run: |
if [[ "${{github.base_ref}}" == "master" || "${{github.ref}}" == "refs/heads/master" ]]; then
echo "::set-output name=gcloud_project::my-project-dev"
echo "::set-output name=phase::staging"
fi
if [[ "${{github.base_ref}}" == "production" || "${{github.ref}}" == "refs/heads/production" ]]; then
echo "::set-output name=gcloud_project::my-project-prd"
echo "::set-output name=phase::production"
fi
print:
runs-on: ubuntu-latest
needs: init
steps:
- name: Print
run: echo "gcloud_project=${{needs.init.outputs.gcloud_project}}"

You can drop the global env statement, combine the event triggers to
on:
push:
branches:
- master
- production
pull_request:
branches:
- master
- production
and then add a first step that checks which branch the workflow is running on and set the environment there:
- name: Set environment for branch
run: |
if [[ $GITHUB_REF == 'refs/heads/master' ]]; then
echo "GLCOUD_PROJECT=my-project-stg" >> "$GITHUB_ENV"
echo "VERCEL_TARGET=staging" >> "$GITHUB_ENV"
else
echo "GLCOUD_PROJECT=my-project-prd" >> "$GITHUB_ENV"
echo "VERCEL_TARGET=production" >> "$GITHUB_ENV"
fi

Things could have changed but for anyone still searching for an answer, there is a way to set a variabe visible for the entire workflow.
jobs:
weekday_job:
runs-on: ubuntu-latest
env:
DAY_OF_WEEK: Mon
Then access by jobs.<job_id>.steps[*].env
More info in the docs

There's now a better way of achieving this using reusable workflows:
https://docs.github.com/en/actions/learn-github-actions/reusing-workflows

Related

Specify job step to run manually when the rest of the GitHub workflow runs automatically

I have a github workflow, that runs automatically on push to branch 'dev' and I would like to have a specific step that only runs in dev and manually triggered.
I know that this is posible using GitLab, by adding "when: manual" to the step but I can't find a way of doing this on GitHub.
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [ dev ]
#pull_request:
# branches: [ dev ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
triage:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/dev'
steps:
- uses: actions/labeler#v4
test-workflow2:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/dev'
steps:
# Runs a set of commands using the runners shell
- name: Deploy latest
run: |
echo the test worked
test-workflow3-manual:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/dev'
steps:
# Runs a set of commands using the runners shell
- name: Deploy latest
run: |
echo the test worked
# when:
# manual ???
Thank you all in advance and have a nice week
Checking the current branch and event should work with an if:
if: ${{ github.ref_name == 'dev' && github.event_name == 'workflow_dispatch' }}
See github context for more details.

Cannot retrieve and display Github env setup in previous step

I am trying to setup a variable in my CI pipeline that I will reuse later (eventually in another job, which I don't know if possible since I don't know if jobs shares variables.. but this is another problem). My pipeline is:
name: CI
on:
pull_request:
branches:
- main
jobs:
test-job:
runs-on: ubuntu-latest
name: test-job
steps:
- name: setup env variable
run: |
BRANCH_NAME=`echo "${{github.head_ref}}"'`
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
echo ${{ env.BRANCH_NAME }}
that last echo doesn't show anything unfortunately. I am sure that BRANCH_NAME is correctly set because before pushing it into the $GITHUB_ENV" I did echo it and it contains data. Plus you can see the name of the branch in the console logs.
Console logs from Github are the following:
1. Run BRANCH_NAME=`echo "test_branch"'`
2. BRANCH_NAME=test_branch >> /home/runner/work/_temp/_runner_file_commands/set_env_9eeeac39-f573-4079-ba62-e1c2019f7aff
3.
So, that final echo ${{ env.BRANCH_NAME }} gives no result. What am I missing?
UPDATE:
As suggested in the comments, I started using workflow variables, in such a way that they are available throughout all the jobs.
The initial setup becomes:
name: CI
on:
pull_request:
branches:
- main
env:
BRANCH_NAME: ""
jobs:
...
I don't like the fact I need to give those variables an empty string value as placeholder and would have preferred declaring and assigning them in one of the jobs itself.. but still. So, now variables are declared before the jobs section, how do I assign a value to them in one of my steps? Meaning, I need to replace the
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
tried already
echo "BRANCH_NAME=$BRANCH_NAME >> ${{ env.BRANCH_NAME }}
or
${{ env.BRANCH_NAME }}=$BRANCH_NAME
but both ways don't work.

Github Actions: using workflow_run based on new tags

I have two workflows: CI (for continuous integration) and CD (for continuous delivery). Both are working fine individually. My goal is to run the CD workflow only when:
A new tag like v1.1.1 is created on the master branch
The CI workflow is finished
To achieve my goal I'm using the workflow_run event. These are the snippets of my workflows files:
ci.yml:
name: CI
on:
push:
tags: v[1-9]+.[0-9]+.[0-9]+
pull_request:
branches: [develop, hotfix*]
cd.yml
name: CD
on:
workflow_run:
workflows: [CI]
branches: [master]
types:
- completed
The current behavior is: when a tag is created in the master branch only the CI workflow run. I've tried putting tags: v[1-9]+.[0-9]+.[0-9]+ in the workflow_run but the behavior is the same.
My question is: how can I achieve my goal? Is it possible?
According to docs you can only use branches option and not tags for workflow_run so I'm afraid that's why your current setting doesn't work.
You have some alternatives though:
You can turn your CD workflow into action and run it as part of your CI with condition:
.github/actiond/cd/action.yml:
name: CD
description: Run CD
runs:
using: composite
steps:
- run: echo "Success!"
shell: bash
CI:
name: CI
on:
push:
tags: v[1-9]+.[0-9]+.[0-9]+
pull_request:
branches: [develop, hotfix*]
jobs:
sucess:
name: Log success
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2
- run: echo "Success!"
- name: Run CD
if: github.event_name == 'push' && contains(github.event.ref, '/tags/')
uses: ./.github/actions/cd
Have it as a separate job that is dependant on CI job using needs option
Converting it to action makes for better encapsulation IMO although requires some work.
You need to put "" around the name of the triggering workflow in cd.yml:
name: CD
on:
workflow_run:
workflows: ["CI"]

How to set workflow env variables depending on branch

I currently have two GitHub actions workflow files that are pretty much identical, only one is configured to react to push/pull_requests on branch master the other on production.
The staging workflow starts like this:
env:
GCLOUD_PROJECT: my-project-stg
VERCEL_TARGET: staging
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
The production workflow starts like:
env:
GCLOUD_PROJECT: my-project-prd
VERCEL_TARGET: production
on:
push:
branches: [ production ]
pull_request:
branches: [ production ]
The rest of the workflow files is the same, so this is clearly not very DRY.
I would like to have 1 single workflow file and somehow switch between two sets of variables based on the branch name. Is there a way to achieve this or am I maybe approach this from the wrong angle?
If it were possible to extend both workflow files on a shared base definition that would also solve it I guess.
It is not possible to set workflow-level environment variables from a job. Each job runs in its own machine and setting an env variable there only affects all of the later steps in that job.
There are currently two ways to share data between jobs; either you create an artifact and use that, or you declare and set job outputs. The latter works for string values.
Here's an example:
name: "Main"
on:
push:
branches:
- master
- production
pull_request:
branches:
- master
- production
jobs:
init:
runs-on: ubuntu-latest
outputs:
gcloud_project: ${{ steps.setvars.outputs.gcloud_project }}
phase: ${{ steps.setvars.outputs.phase }}
steps:
- name: Cancel previous workflow
uses: styfle/cancel-workflow-action#0.4.0
with:
access_token: ${{ github.token }}
- name: Set variables
id: setvars
run: |
if [[ "${{github.base_ref}}" == "master" || "${{github.ref}}" == "refs/heads/master" ]]; then
echo "::set-output name=gcloud_project::my-project-dev"
echo "::set-output name=phase::staging"
fi
if [[ "${{github.base_ref}}" == "production" || "${{github.ref}}" == "refs/heads/production" ]]; then
echo "::set-output name=gcloud_project::my-project-prd"
echo "::set-output name=phase::production"
fi
print:
runs-on: ubuntu-latest
needs: init
steps:
- name: Print
run: echo "gcloud_project=${{needs.init.outputs.gcloud_project}}"
You can drop the global env statement, combine the event triggers to
on:
push:
branches:
- master
- production
pull_request:
branches:
- master
- production
and then add a first step that checks which branch the workflow is running on and set the environment there:
- name: Set environment for branch
run: |
if [[ $GITHUB_REF == 'refs/heads/master' ]]; then
echo "GLCOUD_PROJECT=my-project-stg" >> "$GITHUB_ENV"
echo "VERCEL_TARGET=staging" >> "$GITHUB_ENV"
else
echo "GLCOUD_PROJECT=my-project-prd" >> "$GITHUB_ENV"
echo "VERCEL_TARGET=production" >> "$GITHUB_ENV"
fi
Things could have changed but for anyone still searching for an answer, there is a way to set a variabe visible for the entire workflow.
jobs:
weekday_job:
runs-on: ubuntu-latest
env:
DAY_OF_WEEK: Mon
Then access by jobs.<job_id>.steps[*].env
More info in the docs
There's now a better way of achieving this using reusable workflows:
https://docs.github.com/en/actions/learn-github-actions/reusing-workflows

How to compare a file changes since last action in github actions

In gitlab we have support for CI_COMMIT_BEFORE_SHA and CI_COMMIT_SHA
Whereas in github we only have support for GITHUB_REF which holds SHA of current commit that triggered this action.
My requirement is to find if a particular file changed since last Action execution
Found a way to solve this using event payload - see push event payload:
in .github/workflows/release.yaml
name: release
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2
- name: deploy
run: sh deploy.sh
env:
CI_COMMIT_BEFORE_SHA: ${{ github.event.before }}
CI_COMMIT_SHA: ${{ github.event.after }}
in bin/deploy.sh
HAS_DESIRED_CHANGES=`git diff --name-only $CI_COMMIT_BEFORE_SHA $CI_COMMIT_SHA | grep -E 'path/to/file1|path/to/dir2'`
echo $HAS_DESIRED_CHANGES
HAS_DESIRED_CHANGES=`echo ${#HAS_DESIRED_CHANGES}`
if ! [ $HAS_DESIRED_CHANGES -eq 0 ]
then
echo "Has desired changes, proceed performing necessary actions"
else
echo "No desired changes. Skipping...."
fi