Skip to content

Instantly share code, notes, and snippets.

@maxim
Last active March 29, 2024 16:41
Show Gist options
  • Save maxim/6e15aa45ba010ab030c4 to your computer and use it in GitHub Desktop.
Save maxim/6e15aa45ba010ab030c4 to your computer and use it in GitHub Desktop.
Download assets from private Github releases
#!/usr/bin/env bash
#
# gh-dl-release! It works!
#
# This script downloads an asset from latest or specific Github release of a
# private repo. Feel free to extract more of the variables into command line
# parameters.
#
# PREREQUISITES
#
# curl, wget, jq
#
# USAGE
#
# Set all the variables inside the script, make sure you chmod +x it, then
# to download specific version to my_app.tar.gz:
#
# gh-dl-release 2.1.1 my_app.tar.gz
#
# to download latest version:
#
# gh-dl-release latest latest.tar.gz
#
# If your version/tag doesn't match, the script will exit with error.
TOKEN="<github_access_token>"
REPO="<user_or_org>/<repo_name>"
FILE="<name_of_asset_file>" # the name of your release asset file, e.g. build.tar.gz
VERSION=$1 # tag name or the word "latest"
GITHUB="https://api.github.com"
alias errcho='>&2 echo'
function gh_curl() {
curl -H "Authorization: token $TOKEN" \
-H "Accept: application/vnd.github.v3.raw" \
$@
}
if [ "$VERSION" = "latest" ]; then
# Github should return the latest release first.
parser=".[0].assets | map(select(.name == \"$FILE\"))[0].id"
else
parser=". | map(select(.tag_name == \"$VERSION\"))[0].assets | map(select(.name == \"$FILE\"))[0].id"
fi;
asset_id=`gh_curl -s $GITHUB/repos/$REPO/releases | jq "$parser"`
if [ "$asset_id" = "null" ]; then
errcho "ERROR: version not found $VERSION"
exit 1
fi;
wget -q --auth-no-challenge --header='Accept:application/octet-stream' \
https://$TOKEN:@api.github.com/repos/$REPO/releases/assets/$asset_id \
-O $2
@zero88
Copy link

zero88 commented Jan 4, 2021

If anyone interest, give a try: https://github.com/zero88/gh-release-downloader

@faisalkhanani-ih Yes if GitHub token is in workflow within this private Github repo

@SIMULATAN
Copy link

Thank you so much for making this snippet, it is a real lifesaver!

In my workflow, I had a beta and release feature, but it always gave me back the latest general release, no matter if it was a prerelease or not.
This shouldn't be a big problem if you automate it because there shouldn't be concurent build and release processes at the same time anyway, but I like to be safe, so I made a little improvement to get the latest prerelease or release, what you want:

Replace line 42 with this:
parser=".[] | select(.prerelease == SHOULD_BE_PRERELEASE) | .assets | map(select(.name == \"$FILE\"))[0].id"

If you replace SHOULD_BE_PRERELEASE with true it gives you back the asset id of the latest prerelease,
if you replace it with false, it gives you the asset id of the latest full release.

You can do the same thing for body or draft and stuff, that is just the way you have to filter it.

Hope this helps!

@inhowe
Copy link

inhowe commented Jul 11, 2021

awesome

@GElkayam
Copy link

As we needed some releases that were in the 5th page (so per_page=100 didn't help), I rewrote the query to query latest (it gives latest released) and tag. also needed some more information in the error reporting:

#!/usr/bin/env bash
#
# gh-dl-release! It works!
# 
# This script downloads an asset from latest or specific Github release of a
# private repo. Feel free to extract more of the variables into command line
# parameters.
#
# PREREQUISITES
#
# curl, wget, jq
#
# USAGE
#
# Set all the variables inside the script, make sure you chmod +x it, then
# to download specific version to my_app.tar.gz:
#
#     gh-dl-release 2.1.1 my_app.tar.gz
#
# to download latest version:
#
#     gh-dl-release latest latest.tar.gz
#
# If your version/tag doesn't match, the script will exit with error.

TOKEN="$3"
REPO="$4"
FILE="$2"      # the name of your release asset file, e.g. build.tar.gz
VERSION="$1"                       # tag name or the word "latest"
GITHUB="https://api.github.com"

alias errcho='>&2 echo'

function gh_curl() {
  curl -H "Authorization: token $TOKEN" \
       -H "Accept: application/vnd.github.v3.raw" \
       $@
}

parser=".assets | map(select(.name == \"$FILE\"))[0].id"
if [ "$VERSION" = "latest" ]; then
  # Github should return the latest release first.
  asset_id=`gh_curl -s $GITHUB/repos/$REPO/releases/latest | jq "$parser"`
else
  asset_id=`gh_curl -s $GITHUB/repos/$REPO/releases/tags/$VERSION | jq "$parser"`
fi;

if [ -z "$asset_id" ]; then
  errcho "ERROR: version not found $VERSION"
  exit 1
fi;
if [ "$asset_id" = "null" ]; then
  errcho "ERROR: file $FILE not found in version $VERSION"
  exit 2
fi;

wget -q --auth-no-challenge --header='Accept:application/octet-stream' \
  https://$TOKEN:@api.github.com/repos/$REPO/releases/assets/$asset_id \
  -O $2

@sonibla
Copy link

sonibla commented Nov 29, 2021

For Windows users, I made a PowerShell equivalent
https://gist.github.com/sonibla/a60fc31b244ceba3220b9bb33316798c

@AchalaDias
Copy link

AchalaDias commented Jan 8, 2022

I have updated the code for the latest github api and changed it to supporting for multiple files download. User can set only necessary file names in the array.

TOKEN="<PAT>"
REPO="<REPO>"
VERSION="<RELEASED-VERSION>" 
GITHUB="https://api.github.com"

function gh_curl() {
  curl -H "Authorization: token $TOKEN" \
       -H "Accept: application/vnd.github.v3+json" \
       $@
}

# assets list you want to download
AseertsList=( 
 asset1.zip asset2.zip
)

assets=$(gh_curl -s $GITHUB/repos/$REPO/releases/tags/$VERSION)

for row in $(echo "${assets}" | jq -c '.assets[]'); do
name=$( jq -r  '.name' <<< "${row}" ) 
echo ${name}
    if [[ ${AseertsList[*]} =~ ${name} ]] ; then

        id=$( jq -r  '.id' <<< "${row}" ) 

        wget -q --auth-no-challenge --header='Accept:application/octet-stream' \
        https://$TOKEN:@api.github.com/repos/$REPO/releases/assets/$asset_id \
        -O test/${name}
    fi
done

@shuantsu
Copy link

shuantsu commented Jan 12, 2022

using application/octet-stream as Accept header did the trick for me to download from a private repo

@gpaOliveira
Copy link

Using wget didn't fit my vanilla GH-Hosted-Runners, so I'm dropping here a curl version of that download that worked for me:

curl -L -s -H "Authorization: token $TOKEN" -H 'Accept:application/octet-stream' \
"https://api.github.com/repos/$REPO/releases/assets/$asset_id" \
-o $asset_name

@ringerc
Copy link

ringerc commented Oct 18, 2022

For releases, uses gh release download instead.

gh release download -R MyOrg/MyRepo --pattern 'myproject-*.tar.gz'

for example.

@jamesETsmith
Copy link

Here are the official docs for anyone else who stumbles on this thread which say to do (note octet-stream here bc I was downloading a binary):

curl -L \
  -H "Accept:  application/octet-stream" \ 
  -H "Authorization: Bearer <YOUR-TOKEN>"\
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/repos/OWNER/REPO/releases/assets/ASSET_ID

If (like me) you're confused about the best way to find out ASSET_ID I'd suggest looking at the json output for the latest release, see the docs here and the code here:

curl -L \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer <YOUR-TOKEN>"\
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/repos/OWNER/REPO/releases/latest

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment