checkout
checkout copied to clipboard
(Optionally) Ref to a branch and if it doesn't exist, use default
Hey!
Is there a way to get a ref
to work like an optional OR? For example:
// GITHUB_HEAD_REF being the name of the branch if my google-foo didn't fail me
ref: ${GITHUB_HEAD_REF} || master
My use-case: I have multiple repos that depend on each other sometimes. If they do, they all share the same branch name for a feature (e.g feature/add-tests
). I want to pull the repos with those branches when they exist, but if they don't (as it's not always necessary to change code in all repos), it'll pull master
.
Thanks!
Thinking about this further, I guess I can just run a bash command before this to define the branch name and export a variable to use in the checkout action. But if I have multiple repos this would become a lot of copy paste code for each repo 😄
I'm just wondering wether there's built-in way, or maybe a potential feature?
Looking for the same feature here!
Any updates on this?
Just hit this, this would be so handy. Now I'm thinking I'll also take a route of checking if the branch is available in the other repo.
Is there a workaround for this?
@vinayakkulkarni here is a pattern that I have been using.
https://github.com/hse-project/hse/blob/master/.github/workflows/builds.yaml#L99
Determine if branch exists using git ls-remote
.
I have a similar use case and was hoping actions/checkout would have something like a fallback-to-default
boolean option. For the longest time I've been copy/pasting some ugly bash I wrote, but I recently got tired of it and wrote a composite action. I've included it below. The options you see are all the ones I need for my use case, so I didn't bother adding anything else. Feel free to modify it. Hope you find it useful.
# .github/actions/checkout/action.yml
# This is essentially the same as actions/checkout, but will
# fallback to the default branch if the ref does not exist.
# https://github.com/actions/checkout
name: Checkout
inputs:
fetch-depth:
default: 1
required: false
type: number
path:
default: ''
required: false
type: string
repository:
default: ${{ github.repository }}
required: false
type: string
ref:
default: ''
required: false
type: string
token:
default: ${{ github.token }}
required: false
type: string
runs:
using: composite
steps:
- id: repo
shell: bash
env:
GH_TOKEN: ${{ inputs.token }}
run: |
if [[ -z "${{ inputs.ref }}" ]]
then
if [[ "${{ inputs.repository }}" != "${{ github.repository }}" ]]
then
USING="default branch"
else
USING="$(gh api /repos/${{ inputs.repository }}/commits/${{ github.sha }}/branches-where-head --jq '.[0].name')"
fi
echo "::notice::Checkout: ${{ inputs.repository }} using ${USING}"
echo "::set-output name=ref-exists::true"
else
if git ls-remote --heads --quiet --exit-code https://${{ inputs.token }}@github.com/${{ inputs.repository }}.git ${{ inputs.ref }}
then
echo "::notice::Checkout: ${{ inputs.repository }} using ${{ inputs.ref }}"
echo "::set-output name=ref-exists::true"
else
USING="$(gh api /repos/${{ inputs.repository }} --jq '.default_branch')"
echo "::notice::Checkout: ${{ inputs.repository }} does not have ref ${{ inputs.ref }} (fallback to ${USING})"
echo "::set-output name=ref-exists::false"
echo "::set-output name=default-branch::${USING}"
fi
fi
- if: steps.repo.outputs.ref-exists == 'true'
uses: actions/checkout@v3
with:
fetch-depth: ${{ inputs.fetch-depth }}
path: ${{ inputs.path }}
repository: ${{ inputs.repository }}
ref: ${{ inputs.ref }}
token: ${{ inputs.token }}
- if: steps.repo.outputs.ref-exists == 'false'
uses: actions/checkout@v3
with:
fetch-depth: ${{ inputs.fetch-depth }}
path: ${{ inputs.path }}
repository: ${{ inputs.repository }}
ref: ${{ steps.repo.outputs.default-branch }}
token: ${{ inputs.token }}
For anyone looking for other simple options, you can use continue-on-error
and steps.<step_id>.outcome
to achieve this fallback pretty easily:
steps:
- name: Try checkout on first branch
uses: actions/checkout@v4
id: bad-checkout
continue-on-error: true
with:
repository: actions/checkout
ref: some-bad-branch
# If the first checkout fails, we checkout the `main` branch by default
- name: Fallback to main branch
if: steps.bad-checkout.outcome == 'failure'
uses: actions/checkout@v4
with:
repository: actions/checkout
ref: main