checkout icon indicating copy to clipboard operation
checkout copied to clipboard

(Optionally) Ref to a branch and if it doesn't exist, use default

Open obedparla opened this issue 3 years ago • 6 comments

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!

obedparla avatar May 24 '21 15:05 obedparla

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?

obedparla avatar May 24 '21 15:05 obedparla

Looking for the same feature here!

Any updates on this?

vicmassy avatar Nov 04 '21 16:11 vicmassy

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.

iBotPeaches avatar Dec 06 '21 23:12 iBotPeaches

Is there a workaround for this?

vinayakkulkarni avatar Aug 04 '22 08:08 vinayakkulkarni

@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.

tristan957 avatar Aug 04 '22 14:08 tristan957

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 }}

chingc avatar Oct 02 '22 21:10 chingc

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

YBadiss avatar Apr 04 '24 10:04 YBadiss