Run a certain job depending on the source branch from a PR - github-actions

I have a GitHub action workflow for a swift package that runs whenever something is merged to the main branch.
My goal is to check the for a source branch and depending on its prefix (i.e. patch/something) determine wow to tag and release it.
This is how I have it configured so far:

name: Release
on:
push:
branches:
- main
jobs:
build:
runs-on: macos-latest
patch-release-on-push:
needs: build
if: contains(github.head_ref, 'patch')
runs-on: ubuntu-latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- id: release
uses: rymndhng/release-on-push-action#master
with:
bump_version_scheme: patch
The problem with this is that github.head_ref is null. I only get a value on it if I switch the workflow to be triggered on a pull_request instead of push which wouldn’t really work given that the release would be out before the PR was merged.

What’s the right approach for achieving this?



I would suggest you to use an existing action like EthanSK/git-branch-name-action, as example:
on: [push, pull_request]
jobs:
main_job:
runs-on: ubuntu-latest
steps:
- name: Git branch name
id: git-branch-name
uses: EthanSK/git-branch-name-action#v1
- name: Echo the branch name
run: echo "Branch name ${GIT_BRANCH_NAME}"
and use also like
if: ${{ contains(env.GIT_BRANCH_NAME, 'patch') }}
Link to the marketplace here

Related

Is it possible to share or reuse some job steps inside Github actions?

Giving the following sample Github actions workflow
name: My workflow
on: pull_request
jobs:
foo:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout#v3
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go#v3
with:
go-version: 1.19
- name: Foo
run: echo "foo"
bar:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout#v3
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go#v3
with:
go-version: 1.19
- name: Bar
run: echo "bar"
I want the jobs Foo and Bar to run in parallel. But as you can see they have some steps in common.
Is it possible to create a job that runs the checkout and setup step and provides itself to Foo and Bar so they only have to run their own commands? ( that would save some time, but I don't think that's possible because both jobs run in separate containers )
If that's not possible, is there a way to extract the "duplicate" lines and move them to a "step function" I can call in my jobs so I don't have to write those steps over and over again?
You may use caching to save some time: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows and to consolidate the "duplicated lines in your YAML file" in every job, you may want to have a composite action, where you basically extract
steps:
- name: Checkout repository
uses: actions/checkout#v3
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go#v3
with:
go-version: 1.19
To a new action that you may use in your workflow file to look like:
name: My workflow
on: pull_request
jobs:
foo:
runs-on: ubuntu-latest
steps:
- name: My composite action
uses: path/to/action
- name: Foo
run: echo "foo"
bar:
runs-on: ubuntu-latest
steps:
- name: My composite action
uses: path/to/action
- name: Bar
run: echo "bar"
Note that if you want to create this composite action in the same repository you will have to use actions/checkout#v3 before you call it using a relative URL.
So it will be:
name: My workflow
on: pull_request
jobs:
foo:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout#v3
- name: My composite action
uses: ./.github/actions/my-action.yaml
- name: Foo
run: echo "foo"
bar:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout#v3
- name: My composite action
uses: ./.github/actions/my-action.yaml
- name: Bar
run: echo "bar"
And yes, if you only have only a few steps this approach may not bring much value to you. As you may only save few lines in the YAML file, and you can only cache your dependencies installation.
And, this doesn't mean that your "shared/composite" actions will run only once, Github will re-run each of their steps for each job that's calling them (foo, bar in your case).
One other approach, to consolidate some of the steps you run in your pipelines is by creating a Docker image in which your actions will run, this base docker image may have the necessary setup for you, for example: GoLang, and your necessary build and test modules installation.
name: My workflow
on: pull_request
jobs:
foo:
runs-on: ubuntu-latest
container: mydocker.image.uri/name:version
steps:
- name: Checkout repository
uses: actions/checkout#v3
- name: Foo
run: echo "foo"
bar:
runs-on: ubuntu-latest
container: mydocker.image.uri/name:version
steps:
- name: Checkout repository
uses: actions/checkout#v3
- name: Bar
run: echo "bar"
The gains with this approach are that you may cut some lines out of your workflow file, and you extracted some setup steps to the base docker image, in which you will run your actions.
About the downsides, it might be a little bit challenging to build a stable base image with the necessary setups to run your steps. And also, you will need to maintain another part of your CI/CD pipelines.
One other solution would be the usage of an execution matrix (with Caching dependency files and build outputs), which will run parallel jobs for each of your matrix values (they will be parallelized depending on the runner's availability or by your max-parallel value)
name: My workflow
on: pull_request
jobs:
foo:
runs-on: ubuntu-latest
strategy:
matrix:
greeting: ["hello", "bonjour"]
steps:
- name: Checkout repository
uses: actions/checkout#v3
- name: Setup Go
uses: actions/setup-go#v3
with:
go-version: 1.19
cache: true
- name: Saying ${{ matrix.greeting }}
run: echo "${{ matrix.greeting }}!"
And as you see, all steps re-run again:
which might not be interesting if you are doing more than GoLang setup but doing steps that may take a lot of time
And the last option I have in my mind is to use dependant jobs, which may not work for this use case. But it might be a solution if you can redesign your workflow to produce an output, or a binary from a first step called baz then your workflow would have
foo:
runs-on: ubuntu-latest
needs: baz
steps:
- name: Something
run: echo "baz is saying: ${{ needs.baz.outputs.greeting }}"
I hope this helps or gave you more ideas on how to optimize this workflow further!

What github action can i use in the event of push to get changes that were a part of the commit that was pushed?

Currently, my GitHub workflow looks as follows:
name: learn-github-actions
run-name: ${{ github.actor }} is learning GitHub Actions
on:
push:
branches:
- main
jobs:
update-x:
runs-on: ubuntu-latest
steps:
- name: Git checkout
uses: actions/checkout#v2
with:
# fetch depth is needed since we will be taking git diff with HEAD^1
fetch-depth: 2
- name: Run script
run: scripts/x/x-version-bump.sh
Instead of using git diff in my x-version-bump.sh script I would like to get the changes of the commit pushed via a GitHub action and pass it on to the script. I cannot find a way currently in Github actions to do the same.

Github actions How to only run a step when merging into master

I have been trying to get this right for hours, and nothing I have managed to find has helped. I am trying to setup a github action that will run tests on every pull request into master and any changes to the master branch, but only run the deploy step when there are changes to the master branch.
Here is a simple reproduction of what I am trying to do.
name: Main
on:
push:
branches:
- "main"
pull_request:
branches:
- "main"
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2
- name: Test
run: echo "running tests"
- name: Deploy
run: echo "Deploying"
if: github.head_ref == 'main'
I have tried multiple conditionals I have found here / on other forums, I have tried moving the if statement above and below run I am completely out of ideas. Everything I have tried either runs the deploy step on both pull request and merge or skips the deploy step on both pull request and merge.
Just use:
github.ref == 'refs/heads/master'
or:
github.ref == 'refs/heads/main'
Depending on which branch you want to check
This is what I do:
build:
runs-on: [...]
steps:
- name: Echo on merging to master
if: ${{ github.ref == 'refs/heads/master' }}
run: echo "I'm merging!"

Prevent GitHub Action to run for each tag on a commit

I have a publish workflow that is supposed to push the dists to PyPi if a commit on main is tagged with either frontend-v* or backend-v* (both are separate packages)
However, if a commit has changes on both the front- and backend and I add two tags to the commit, the workflow is triggered twice.
I understand that I could simply split the workflow into two, but I have another job that should run if either frontend or backend or both were updated which should only be ran once, thus I want to keep this in one workflow.
Can I somehow circumvent this to run this only once?
Thank you very much!
on:
workflow_dispatch:
push:
branches: [ main ]
tags:
- frontend*
- backend*
jobs:
backend:
name: Publish backend
if: ${{contains(github.ref_name, 'backend') }}
runs-on: ubuntu-latest
steps:
...
frontend:
name: Publish frontend
if: ${{contains(github.ref_name, 'frontend') }}
runs-on: ubuntu-latest
steps:
...
housekeeping: # this should only be ran once for the commit
name: House Keeping
runs-on: ubuntu-latest
steps:
...

Github action jobs triggered by different events

My release pipeline in Github action has two jobs (1) Testing (2) Release
This is what I am aim to achieve:
The testing job of the release pipeline will be triggered by creating a pull-request, the release job of the pipeline will be rung when pull-request is merged
name: OC-API CD
on:
pull_request:
types: [merged]
branches:
- master
jobs:
testing:
runs-on: ubuntu-latest
steps:
...
release:
runs-on: ubuntu-latest
steps:
...
It seems all jobs has to be triggered by the same events via on,
(1) Is there any way that different job can be triggered by different events?
(2) How can I add dependency between testing and release, AKA, the release job is depend on the successfully runs the testing job
You can control each job by adding if, in your case it will be like this:
jobs:
testing:
if: ${{ github.event.action }} == 'opened'
runs-on: ubuntu-latest
steps:
...
Keep in mind you have to add opened to a on: pull_request: types: array of course :)
For the second part you can add dependency using needs, like this:
jobs:
testing:
runs-on: ubuntu-latest
steps:
...
release:
needs: testing
runs-on: ubuntu-latest
steps:
...