Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make reference accessible in reusable workflow #1264

Open
kagahd opened this issue Dec 13, 2022 · 26 comments
Open

make reference accessible in reusable workflow #1264

kagahd opened this issue Dec 13, 2022 · 26 comments
Labels
enhancement New feature or request

Comments

@kagahd
Copy link

kagahd commented Dec 13, 2022

Describe the enhancement

A reusable workflow should be able to access the reference that it was called for.

Context

A reusable workflow in public repos may be called by appending a reference which can be a SHA, a release tag, or a branch name, as for example:
{owner}/{repo}/.github/workflows/{filename}@{ref}

Githubs documentation states:

When a reusable workflow is triggered by a caller workflow, the github context is always associated with the caller workflow.

The problem

Since the github context is always associated with the caller workflow, the reusable workflow cannot access the reference, for example the tag v1.0.0. However, knowing the reference is important when the reusable workflow needs to checkout the repository in order to make use of composite actions.

Code snippet

Assume that the caller workflow is being executed from within the main branch and calls the ref v1.0.0. of a reusable workflow:

name: Caller workflow
on:
  workflow_dispatch:

jobs:
  caller:
    uses: owner/public-repo/.github/workflows/reusable-workflow.yml@v1.0.0

Here is the reusable workflow that uses a composite action:

name: reusable workflows
on:
  workflow_call:

jobs:
  first-job:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3.1.0
        with:
          repository: owner/public-repo
          ref: ${{ github.ref_name }}

      - name: composite action
        uses: ./actions/my-composite-action

In the above code snippet, ${{ github.ref_name }} is main instead of v1.0.0 because github context is always associated with the caller workflow. Therefore, the composite actions code is based on main and not on v1.0.0.

Proposal

Introduce a new github context variable caller_ref which reflects the reference indicated by the caller.
The reusable workflow could then use it as follows:

name: reusable workflows
on:
  workflow_call:

jobs:
  first-job:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3.1.0
        with:
          repository: owner/public-repo
          ref: ${{ github.caller_ref }}

      - name: composite action
        uses: ./actions/my-composite-action

Or even shorter without the need to checkout:

name: reusable workflows
on:
  workflow_call:

jobs:
  first-job:
    runs-on: ubuntu-latest
    steps:
      - name: composite action
        uses: ./actions/my-composite-action@${{ github.caller_ref }}

Now, the composite action would be using v1.0.0. as indicated by the caller.

Related to this FR:

@kagahd kagahd added the enhancement New feature or request label Dec 13, 2022
@cbrzn
Copy link

cbrzn commented Jan 27, 2023

I have the same issue, and would love some help!

@carlcsaposs-canonical
Copy link

carlcsaposs-canonical commented Feb 9, 2023

Ran into the same issue, here's a workaround: https://github.com/canonical/data-platform-workflows/blob/main/.github/workflows/_get_workflow_version.yaml

To solve this, we're now using this composite action (that implements @maxbergs's solution)

https://github.com/canonical/get-workflow-version-action

Example usage:

# Reusable workflow (e.g. build_charm.yaml)
on:
  workflow_call:

jobs:
  foo:
    runs-on: ubuntu-latest
    steps:
      - name: Get workflow version
        id: workflow-version
        uses: canonical/get-workflow-version-action@v1
        with:
          repository-name: canonical/data-platform-workflows
          file-name: build_charm.yaml
      # Use the version. For example:
      - name: Install Python CLI
        run: pipx install git+https://github.com/canonical/data-platform-workflows@'${{ steps.workflow-version.outputs.sha }}'#subdirectory=python/cli

@mjhipp
Copy link

mjhipp commented Feb 24, 2023

I am also interested in a solution for this. My use case is I have a repository within my org where I put shared workflows as well as composite actions. I often want to use composite actions within my reusable workflow in the same repository.

I see that you can do this with reusable workflows, but not yet composite actions: https://github.blog/changelog/2022-01-25-github-actions-reusable-workflows-can-be-referenced-locally/

mjhipp/shared-actions
├── actions
│   └── my-composite-action
│       └── action.yml
└── workflows
    └── my-reusable-workflow.yml
name: My Reusable Workflow
on:
  workflow_call:
jobs:
  my-reusable-workflow:
    runs-on: ubuntu-latest:
    steps:
      - uses: mjhipp/shared-actions/actions/my-composite-action@{???}

I would like to use whatever version I am using for the shared workflow for the called composite action, from the same repo as the called workflow.
I could use 'main', but I like to pin version tags in my actions for safety.

@jrosend
Copy link

jrosend commented May 2, 2023

I'd love this new reference to be created as well. I'm facing the same problem.

@dstuck
Copy link

dstuck commented May 11, 2023

Presumably the github.job_workflow_sha which is "For jobs using a reusable workflow, the commit SHA for the reusable workflow file" should solve this but it appears that this variable isn't ever populated: actions/runner#2417

@GustavoKatel
Copy link

I am also interested in a solution for this. My use case is I have a repository within my org where I put shared workflows as well as composite actions. I often want to use composite actions within my reusable workflow in the same repository.

I see that you can do this with reusable workflows, but not yet composite actions: https://github.blog/changelog/2022-01-25-github-actions-reusable-workflows-can-be-referenced-locally/

mjhipp/shared-actions
├── actions
│   └── my-composite-action
│       └── action.yml
└── workflows
    └── my-reusable-workflow.yml
name: My Reusable Workflow
on:
  workflow_call:
jobs:
  my-reusable-workflow:
    runs-on: ubuntu-latest:
    steps:
      - uses: mjhipp/shared-actions/actions/my-composite-action@{???}

I would like to use whatever version I am using for the shared workflow for the called composite action, from the same repo as the called workflow. I could use 'main', but I like to pin version tags in my actions for safety.

I have the same use case and having this implemented would be great for pinning version between the reusable and the composite action

joverlee521 added a commit to nextstrain/.github that referenced this issue May 24, 2023
Add a reusable workflow to run Nextstrain builds so that we can
centralize and standardize how our pathogen repos set up these builds.
Motivated by the latest hiccup with the Snakemake upgrade
that required fixes across multiple pathogen repos.¹

There are some "hacky" steps to get around the limitations of reusable
workflows:

1. The 'ref' input is required to ensure that we checkout the matching
ref within the reusable workflow since it is currently not possible to
detect the called workflow's ref.²
2. Since reusable workflows cannot access environment variables set in
the calling workflow, this uses the yaml-to-envvars workaround with an
`env` input already used in the patheogen-repo-ci workflow.³
3. We use a json-to-envvars workaround to allow for setting secrets
as environment variables for the build runtime dynamically.

¹ https://bedfordlab.slack.com/archives/C01LCTT7JNN/p1681328249848399
² actions/toolkit#1264
³ https://github.com/nextstrain/.github/blob/cc6f4385a45bd6ed114ab4840416fd90cc46cd1b/.github/workflows/pathogen-repo-ci.yaml#L25-L45
joverlee521 added a commit to nextstrain/.github that referenced this issue May 25, 2023
Add a reusable workflow to run Nextstrain builds so that we can
centralize and standardize how our pathogen repos set up these builds.
Motivated by the latest hiccup with the Snakemake upgrade
that required fixes across multiple pathogen repos.¹

There are some "hacky" steps to get around the limitations of reusable
workflows:

1. The 'ref' input is required to ensure that we checkout the matching
ref within the reusable workflow since it is currently not possible to
detect the called workflow's ref.²
2. Since reusable workflows cannot access environment variables set in
the calling workflow, this uses the yaml-to-envvars workaround with an
`env` input already used in the patheogen-repo-ci workflow.³
3. We use a json-to-envvars workaround to allow for setting secrets
as environment variables for the build runtime dynamically.

¹ https://bedfordlab.slack.com/archives/C01LCTT7JNN/p1681328249848399
² actions/toolkit#1264
³ https://github.com/nextstrain/.github/blob/cc6f4385a45bd6ed114ab4840416fd90cc46cd1b/.github/workflows/pathogen-repo-ci.yaml#L25-L45
joverlee521 added a commit to nextstrain/.github that referenced this issue May 25, 2023
Add a reusable workflow to run Nextstrain builds so that we can
centralize and standardize how our pathogen repos set up these builds.
Motivated by the latest hiccup with the Snakemake upgrade
that required fixes across multiple pathogen repos.¹

There are some "hacky" steps to get around the limitations of reusable
workflows:

1. The 'ref' input is required to ensure that we checkout the matching
ref within the reusable workflow since it is currently not possible to
detect the called workflow's ref.²
2. Since reusable workflows cannot access environment variables set in
the calling workflow, this uses the yaml-to-envvars workaround with an
`env` input already used in the patheogen-repo-ci workflow.³
3. We use a json-to-envvars workaround to allow for setting secrets
as environment variables for the build runtime dynamically.

¹ https://bedfordlab.slack.com/archives/C01LCTT7JNN/p1681328249848399
² actions/toolkit#1264
³ https://github.com/nextstrain/.github/blob/cc6f4385a45bd6ed114ab4840416fd90cc46cd1b/.github/workflows/pathogen-repo-ci.yaml#L25-L45
joverlee521 added a commit to nextstrain/.github that referenced this issue May 25, 2023
Add a reusable workflow to run Nextstrain builds so that we can
centralize and standardize how our pathogen repos set up these builds.
Motivated by the latest hiccup with the Snakemake upgrade
that required fixes across multiple pathogen repos.¹

There are some "hacky" steps to get around the limitations of reusable
workflows:

1. The 'ref' input is required to ensure that we checkout the matching
ref within the reusable workflow since it is currently not possible to
detect the called workflow's ref.²
2. Since reusable workflows cannot access environment variables set in
the calling workflow, this uses the yaml-to-envvars workaround with an
`env` input already used in the patheogen-repo-ci workflow.³
3. We use a json-to-envvars workaround to allow for setting secrets
as environment variables for the build runtime dynamically.

¹ https://bedfordlab.slack.com/archives/C01LCTT7JNN/p1681328249848399
² actions/toolkit#1264
³ https://github.com/nextstrain/.github/blob/cc6f4385a45bd6ed114ab4840416fd90cc46cd1b/.github/workflows/pathogen-repo-ci.yaml#L25-L45
joverlee521 added a commit to nextstrain/.github that referenced this issue May 25, 2023
Add a reusable workflow to run Nextstrain builds so that we can
centralize and standardize how our pathogen repos set up these builds.
Motivated by the latest hiccup with the Snakemake upgrade
that required fixes across multiple pathogen repos.¹

There are some "hacky" steps to get around the limitations of reusable
workflows:

1. The 'ref' input is required to ensure that we checkout the matching
ref within the reusable workflow since it is currently not possible to
detect the called workflow's ref.²
2. Since reusable workflows cannot access environment variables set in
the calling workflow, this uses the yaml-to-envvars workaround with an
`env` input already used in the patheogen-repo-ci workflow.³
3. We use a json-to-envvars workaround to allow for setting secrets
as environment variables for the build runtime dynamically.

¹ https://bedfordlab.slack.com/archives/C01LCTT7JNN/p1681328249848399
² actions/toolkit#1264
³ https://github.com/nextstrain/.github/blob/cc6f4385a45bd6ed114ab4840416fd90cc46cd1b/.github/workflows/pathogen-repo-ci.yaml#L25-L45
joverlee521 added a commit to nextstrain/.github that referenced this issue May 25, 2023
Add a reusable workflow to run Nextstrain builds so that we can
centralize and standardize how our pathogen repos set up these builds.
Motivated by the latest hiccup with the Snakemake upgrade
that required fixes across multiple pathogen repos.¹

There are some "hacky" steps to get around the limitations of reusable
workflows:

1. The 'ref' input is required to ensure that we checkout the matching
ref within the reusable workflow since it is currently not possible to
detect the called workflow's ref.²
2. Since reusable workflows cannot access environment variables set in
the calling workflow, this uses the yaml-to-envvars workaround with an
`env` input already used in the patheogen-repo-ci workflow.³
3. We use a json-to-envvars workaround to allow for setting secrets
as environment variables for the build runtime dynamically.

¹ https://bedfordlab.slack.com/archives/C01LCTT7JNN/p1681328249848399
² actions/toolkit#1264
³ https://github.com/nextstrain/.github/blob/cc6f4385a45bd6ed114ab4840416fd90cc46cd1b/.github/workflows/pathogen-repo-ci.yaml#L25-L45
@cezar-tech
Copy link

Also having this need in my enterprise

@apascual
Copy link

This is a basic feature need for using reusable workflows. We need a way to keep reusable workflows and the rest of the associated scripting in the same repository so we can version or do branch development. Please, provide a solution to access some context of the reused workflow, ideally access to local files and current branch/tag.

@lcharest-godaddy
Copy link

Piling on. My org really needs this.

@carloseduardosx
Copy link

I'm also interested in a solution for this.

My org has a central repo with our Reusable Workflows and Shared Action, and it would be essential for us to call the Shared Action using the same revision of the Reusable Workflow.

@corest
Copy link

corest commented Sep 14, 2023

+1 for this
For now I came up with workaround I'm sharing below.

So I have repository org/workflows with structure:

.github/workflows/shared.yml
actions/action1
actions/action2

.github/workflows/shared.yml is using action/action1 and action/action2 actions inside via e.g. uses: ./action/action.

Repository app calls shared workflow via uses: org/workflows/.github/workflows/shared.yml@v1.0.0.
So we need to know value v1.0.0 in shared workflow to properly checkout reference with local actions.

Here is how it is done in .github/workflows/shared.yml:

jobs:

  action1:
    name: Extract metadata
    runs-on: ubuntu-latest
    steps:

      - name: Checkout calling repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 1

      - name: Get workflow reference
        id: workflows-ref
        run: |
          workflow_ref=${{ github.workflow_ref }}
          repository="${{ github.repository }}/"
          repo_ref="@${{ github.ref }}"
          workflow_path=${workflow_ref#"$repository"}
          workflow_path=${workflow_path%"$repo_ref"}

          ref=$(cat ${workflow_path} | grep pull-request-java-app | cut -d"@" -f2)
          echo "ref=${ref}" >> ${GITHUB_OUTPUT}

      - name: Checkout workflows
        uses: actions/checkout@v4
        with:
          ref: ${{ steps.workflows-ref.outputs.ref }} # use ref
          repository: org/workflows
          token: ${{ secrets.CIJOBTOKENWRITE }}
          path: workflows # checkout into separate folder

      - name: action1
        id: action1
        uses: ./workflows/actions/action1

@maxbergs
Copy link

The workaround to this problem that we found was the most clean and easy was to simply do a curl request to get the SHA from the workflow run and use that in ref (https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#get-a-workflow-run).

Example (I don't think I missed anything):

jobs:
  Metadata:
    name: Extract metadata
    runs-on: ubuntu-latest
    permissions:
      actions: read    
    outputs:
      caller-sha: ${{ steps.workflows-ref.outputs.caller-sha }}
    steps:
      - name: Get workflow reference
        id: workflows-ref
        run: |
          sha=$(curl -L -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/<owner>/<repo>/actions/runs/${{ github.run_id }} | jq -r '.referenced_workflows[0] | .sha')
          echo "caller-sha=$sha" >> $GITHUB_OUTPUT
  Test:
    needs: [Metadata]
    uses: ./.github/workflows/test.yml
    secrets: inherit
    with:
      version: ${{ needs.Metadata.outputs.caller-sha }}          

And then in ./.github/workflows/test.yml:

on:
  workflow_call:
    inputs:
      version:
        required: true
        type: string
jobs:
  Test:
    runs-on: ubuntu-latest
    steps:
      - name: Check out actions
        uses: actions/checkout@v4
        with:
          repository: <repo> 
          ref: ${{ input.version }}
          token: <secrets.TOKEN> ##you need a PAT-token with read rights to the repo

@pdmtt
Copy link

pdmtt commented Jan 22, 2024

I'm facing this problem too.

Our reusable workflow needs to checkout its own repository in order to execute a Python script. Allowing access to the called workflow repo's reference would enable versioning its behaviour.

Any developments on this? Thanks!

addyess added a commit to canonical/k8s-workflows that referenced this issue Jan 30, 2024
@shermanericts
Copy link

The workaround to this problem that we found was the most clean and easy was to simply do a curl request to get the SHA from the workflow run and use that in ref (https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#get-a-workflow-run).

Example (I don't think I missed anything):

jobs:
  Metadata:
    name: Extract metadata
    runs-on: ubuntu-latest
    permissions:
      actions: read    
    outputs:
      caller-sha: ${{ steps.workflows-ref.outputs.caller-sha }}
    steps:
      - name: Get workflow reference
        id: workflows-ref
        run: |
          sha=$(curl -L -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/<owner>/<repo>/actions/runs/${{ github.run_id }} | jq -r '.referenced_workflows[0] | .sha')
          echo "caller-sha=$sha" >> $GITHUB_OUTPUT
  Test:
    needs: [Metadata]
    uses: ./.github/workflows/test.yml
    secrets: inherit
    with:
      version: ${{ needs.Metadata.outputs.caller-sha }}          

And then in ./.github/workflows/test.yml:

on:
  workflow_call:
    inputs:
      version:
        required: true
        type: string
jobs:
  Test:
    runs-on: ubuntu-latest
    steps:
      - name: Check out actions
        uses: actions/checkout@v4
        with:
          repository: <repo> 
          ref: ${{ input.version }}
          token: <secrets.TOKEN> ##you need a PAT-token with read rights to the repo

This was a life-saver for me today. Thank you!

@Ilyes512
Copy link

I don't understand how such obvious requirement is missing... this is one of the first things I immediately needed when extracting workflows and composite actions to the same repo.

It seems like there is not enough dogfeeding happening at Github. :/

@earlye
Copy link

earlye commented Apr 17, 2024

This is definitely a thing that still matters. We're in the process of building out shared workflows that are composed of, well, composite actions in the same repository, and having to manually specify a branch as we modify those composite actions in the workflow file is tedious and error prone. Would be much better to be able to say:

  - uses: {path-to-workflow}/@${{ github.referenced_workflows[0].sha }}

@carlcsaposs-canonical
Copy link

In case it helps anyone, we created a composite action that implements @maxbergs's solution

https://github.com/canonical/get-workflow-version-action

Example usage:

# Reusable workflow (e.g. build_charm.yaml)
on:
  workflow_call:

jobs:
  foo:
    runs-on: ubuntu-latest
    steps:
      - name: Get workflow version
        id: workflow-version
        uses: canonical/get-workflow-version-action@v1
        with:
          repository-name: canonical/data-platform-workflows
          file-name: build_charm.yaml
      # Use the version. For example:
      - name: Install Python CLI
        run: pipx install git+https://github.com/canonical/data-platform-workflows@'${{ steps.workflow-version.outputs.sha }}'#subdirectory=python/cli

@ckmoga
Copy link

ckmoga commented Jul 7, 2024

We have reusable workflows to build docker images and deploy microservices. The docker image workflow is triggered when a version is created and we use ${GITHUB_REF#refs/*/} to extract it.
From what people say above, we must write a composite action to handle this before calling the reusable workflow. This is ok when you have few repos but it becomes daunting when you have 40+ microservices.

We currently copy & paste the workflows because there is not much benefit to using the reusable workflows.
Is there is no other way to do this more efficiently, other than composite actions?

@carlcsaposs-canonical
Copy link

@ckmoga I don't understand exactly what you're trying to accomplish, but it doesn't sound like you're affected by this issue

GITHUB_REF (or ${{ github.ref }}) is available in a reusable workflow

This issue is about accessing the ref that a reusable workflow was called with—i.e. the version of the reusable workflow—not about accessing the ref of the caller repository that triggered the workflow run

@ckmoga
Copy link

ckmoga commented Jul 8, 2024

@carlcsaposs-canonical it is possible that I am missing something but I cannot get my release number using ${GITHUB_REF#refs/*/}
It is empty but in ordinary workflow it is correct

@carlcsaposs-canonical
Copy link

@ckmoga
Copy link

ckmoga commented Jul 8, 2024

OK @carlcsaposs-canonical I got it working with $GITHUB_REF_NAME. ${{ github.ref }} throws unknown reference somehow. I think my issue was the curly brackets: ${GITHUB_REF}

@stf976
Copy link

stf976 commented Aug 28, 2024

In case it helps anyone, we created a composite action that implements @maxbergs's solution

It's not obvious to me what the advantage of this solution is over directly passing the called workflow repo and ref as workflow inputs. Especially since for the action you need the repo and file name to get the ref.

The repo and file name of the called workflow might change, hence should not be hard-coded in the called workflow file.

You already know the repo, ref, and file name in the caller. So you could pass the repo and file name to the called workflow to execute the action, or just pass repo and ref and skip the action step.

@carlcsaposs-canonical
Copy link

It's not obvious to me what the advantage of this solution is over directly passing the called workflow repo and ref as workflow inputs. Especially since for the action you need the repo and file name to get the ref.

For us, it's helpful because the repository name and workflow name are determined by the reusable workflow, but the ref is determined by the caller. (So it's easy to hard code repository name & workflow name in the reusable workflow)

We prefer having one source of truth instead of duplicating it as an input (which could lead to mistakes), and because we use tools like Renovate to update our refs (which are not easily capable of also updating that input)

But that's just what works for us—if passing the ref as an input works for you, there's no need to use an action that calls the GitHub API

@dariocurr
Copy link

Hi guys, following this discussion and looking for a solution I created the following basic action to facilitate what @maxbergs provided us: dariocurr/checkout-called.

I hope it will be useful. The only difficult part, IMHO, might be creating the token with the correct set of permissions

@randallt21
Copy link

@dariocurr Thank you so much for creating this action! Worked perfectly.

Leaving this comment so others know to use it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests