How to conditionally run Github workflow action only for tags made on specific branch?

I am using a couple different Github workflows including one that should only run on official releases. Inside the .github/workflows/release.yml is this on condition:

on:
  push:
    tags:
      - 'v*'

However, this can still run if someone on our team accidentally (or purposely) pushes a tag from the develop branch. Ideally, we would want to lock this down so that the tag MUST be on the main branch (since that is protected), and maybe even further, it would be nice if we could ensure that the tags are only referencing the specific merge commit relating to the corresponding release. For example, if I run

git branch --contains tags/v1.2.3

this would normally output the main branch where I made the tag. Can I add a condition to the github workflow to check the output of that?

Looking at the Github action documentation it is not clear if multiple conditions are evaluated using a logical AND or a logical OR.


Solution 1:

The events types specified in on have a logical OR between them. So for example

on:
  push:
    tags: ['v[0-9].[0-9]+.[0-9]+']
    branches: [master]

would unfortunately trigger the workflow for any matching tag on any branch but also any push on master with or without tags. I also updated the tag pattern following the example from the doc.

You will have to decide if you want to run the workflow only for tags and then filter out anything else than master:

on:
  push:
    tags: ['v[0-9].[0-9]+.[0-9]+']

jobs:
  myjob:
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/master'
    steps: [...]

or the other way around:

on:
  push:
    branches: [master]

jobs:
  myjob:
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/v')
    steps: [...]

You might pick the second solution if, for example, your workflow contains other jobs that might run on pushes to master. As you will also notice, the filter of the tag is less accurate on the second one and it might become an issue. It is also important to note that you can skip whole workflows using the conditions in on, whole jobs with jobs.<job_id>.if but also just steps with jobs.<job_id>.steps[*].if