Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save gvenzl/1386755861fb42db492276d3864a378c to your computer and use it in GitHub Desktop.
Save gvenzl/1386755861fb42db492276d3864a378c to your computer and use it in GitHub Desktop.
One Liner to download the latest release from your GitHub repo
LOCATION=$(curl -s https://api.github.com/repos/<YOUR ORGANIZTION>/<YOUR REPO>/releases/latest \
| grep "zipball_url" \
| awk '{ print $2 }' \
| sed 's/,$//'       \
| sed 's/"//g' )     \
; curl -L -o <OUTPUT FILE NAME> $LOCATION

for example:

LOCATION=$(curl -s https://api.github.com/repos/csv2db/csv2db/releases/latest \
| grep "zipball_url" \
| awk '{ print $2 }' \
| sed 's/,$//'       \
| sed 's/"//g' )     \
; curl -L -o csv2db.zip $LOCATION

Here is how it goes:

LOCATION=$(...)

stores the output of all the commands in the brackets in the variable $LOCATION

curl -s https://api.github.com/repos/csv2db/csv2db/releases/latest

gets the latest release from your repository, in my case github.com/csv2db/csv2db

grep "zipball_url"

grabs the line for the zipball URL of the file --> "zipball_url": "https://api.github.com/repos/csv2db/csv2db/zipball/v1.5.1",
Note, there is also a tarball_url if you prefer the .tar.gz file instead.

awk '{ print $2 }'

prints just the URL part of the zipball_url line --> "https://api.github.com/repos/csv2db/csv2db/zipball/v1.5.1",

sed 's/,$//'

removes the comma , at the end of the line --> "https://api.github.com/repos/csv2db/csv2db/zipball/v1.5.1"

sed 's/"//g'

removes the double quotes " from the previous output --> https://api.github.com/repos/csv2db/csv2db/zipball/v1.5.1

Once all these commands are executed, the string is stored in the $LOCATION variable due to the surrounding $(...). The next step is to download the file from that location (or, at this stage you can do anything else you like with $LOCATION).

curl -L -o csv2db.zip $LOCATION

invokes cURL and downloads $LOCATION into a file called csv2db.zip. The -L parameter is important so that cURL follows the URL, i.e. redirects on the web page, in case that the URL gets forwarded to https or another location on the server. cURL also has an option to just store the file name under the remove file name. This can be done via -O (uppercase O) rather than -o. If you are using -O you are also advised to use -J which tells the -O option to use the server-specified Content-Disposition filename instead of extracting a filename from the URL.

@alecthegeek
Copy link

Awesome. Thanks for this. I shortened it to

latest_tag=$(curl -s https://api.github.com/repos/swagger-api/swagger-ui/releases/latest | sed -Ene '/^ *"tag_name": *"(v.+)",$/s//\1/p')
echo "Using version $latest_tag"
curl -JLO https://github.com/swagger-api/swagger-ui/archive/$latest_tag.tar.gz

Very handy for Docker files and CI/CD pipelines.

(you could of course make it one line, but I did want to display the version name)

@gvenzl
Copy link
Author

gvenzl commented Mar 3, 2021

Very cool, thanks for adding your version to this! :)
I wasn't aware of the api.github.com part.
Looks like one could shoot straight for tarball_url or zipball_url as well if all that is wanted is the file itself:

location=$(curl -s https://api.github.com/repos/csv2db/csv2db/releases/latest | grep tarball_url | awk '{ print $2 }' | sed 's/,$//' | sed 's/"//g' );

There is probably still some further optimization that can be done on the awk and sed parts there :)

@gijsbers
Copy link

eval wget $(curl -s https://api.github.com/repos/ice-wm/icewm/releases/latest  | grep browser_download_url | cut -d : -f 2,3)

@gvenzl
Copy link
Author

gvenzl commented Jan 29, 2022

Very nice, thanks a lot for this addition!

Unfortunately, wget doesn't seem to be available by default on Mac and also the browser_download_url is not always a given:

% curl -s https://api.github.com/repos/csv2db/csv2db/releases/latest  | grep browser_download_url
% curl -s https://api.github.com/repos/csv2db/csv2db/releases/latest  | grep url
  "url": "https://api.github.com/repos/csv2db/csv2db/releases/24743911",
  "assets_url": "https://api.github.com/repos/csv2db/csv2db/releases/24743911/assets",
  "upload_url": "https://uploads.github.com/repos/csv2db/csv2db/releases/24743911/assets{?name,label}",
  "html_url": "https://github.com/csv2db/csv2db/releases/tag/v1.5.1",
    "avatar_url": "https://avatars.githubusercontent.com/u/4610293?v=4",
    "url": "https://api.github.com/users/gvenzl",
    "html_url": "https://github.com/gvenzl",
    "followers_url": "https://api.github.com/users/gvenzl/followers",
    "following_url": "https://api.github.com/users/gvenzl/following{/other_user}",
    "gists_url": "https://api.github.com/users/gvenzl/gists{/gist_id}",
    "starred_url": "https://api.github.com/users/gvenzl/starred{/owner}{/repo}",
    "subscriptions_url": "https://api.github.com/users/gvenzl/subscriptions",
    "organizations_url": "https://api.github.com/users/gvenzl/orgs",
    "repos_url": "https://api.github.com/users/gvenzl/repos",
    "events_url": "https://api.github.com/users/gvenzl/events{/privacy}",
    "received_events_url": "https://api.github.com/users/gvenzl/received_events",
  "tarball_url": "https://api.github.com/repos/csv2db/csv2db/tarball/v1.5.1",
  "zipball_url": "https://api.github.com/repos/csv2db/csv2db/zipball/v1.5.1",

@gijsbers
Copy link

gijsbers commented Feb 6, 2022

wget is like curl -O.

Copy link

ghost commented Apr 8, 2022

@gvenzl Can you help me do the one-liner to grab the latest .zst file of this?

@gvenzl
Copy link
Author

gvenzl commented Jun 25, 2022

Hey @pc00per, here you go: LOCATION=$(curl -s https://api.github.com/repos/ungoogled-software/ungoogled-chromium-archlinux/releases/latest | grep browser_download_url | grep .zst | grep -v debug | awk '{ print $2 }' | sed 's/,$//' | sed 's/"//g'); curl -L -O $LOCATION

That will get you the latest non-debug .zst file.

Copy link

ghost commented Jun 25, 2022

@gvenzl thank you.

@gvenzl
Copy link
Author

gvenzl commented Jun 26, 2022

You are welcome, @pc00per!

@HybridDog
Copy link

It is also possible to use the Command-line JSON processor jq:

RELEASE_API_URL="https://api.github.com/repos/csv2db/csv2db/releases/latest"
TARBALL_URL=$(curl --silent "$RELEASE_API_URL" | jq --raw-output '.tarball_url')
curl --location --silent "$TARBALL_URL" | tar --extract --gzip --file=-
cd csv2db-csv2db-*/

@alecthegeek
Copy link

alecthegeek commented Sep 11, 2022

Nice

if you didn't want to install jq then this also works

curl -s https://api.github.com/repos/swagger-api/swagger-ui/releases/latest |
sed -Ene '/^[[:blank:]]+"tarball_url":[[:blank:]]"(https:[^"]+)",/s//\1/p'

@doctorfree
Copy link

This is great. Thanks! I am testing incorporation of a customized version of this in the MusicPlayerPlus project. That project has release assets for a variety of operating system platforms and architectures. I extended this gist to detect which platform/architecture is the target environment and then, if a release asset is found for that target, automatically install it. This is currently in test. Do you see any problems or have suggestions for how I have extended this gist? This came along right when I needed it. Good timing!

#!/bin/bash

OWNER=<repository_owner>
PROJECT=<repository_name>
API_URL="https://api.github.com/repos/${OWNER}/${PROJECT}/releases/latest"

arch=
centos=
debian=
fedora=
mach=`uname -m`

. /etc/os-release
[ "${ID_LIKE}" == "debian" ] && debian=1
[ "${ID}" == "arch" ] && arch=1
[ "${ID}" == "centos" ] && centos=1
[ "${ID}" == "fedora" ] && fedora=1

DL_URL=
if [ "${arch}" ]
then
  DL_URL=$(curl --silent "${API_URL}" | \
           jq --raw-output '.assets | .[].browser_download_url' | \
           grep "\.pkg\.tar\.zst")
else
  if [ "${centos}" ]
  then
    DL_URL=$(curl --silent "${API_URL}" | \
             jq --raw-output '.assets | .[].browser_download_url' | \
             grep "\.el.*x86_64\.rpm")
  else
    if [ "${fedora}" ]
    then
      DL_URL=$(curl --silent "${API_URL}" | \
               jq --raw-output '.assets | .[].browser_download_url' | \
               grep "\.fc.*x86_64\.rpm")
    else
      if [ "${debian}" ]
      then
        if [ "${mach}" == "x86_64" ]
        then
          DL_URL=$(curl --silent "${API_URL}" | \
                   jq --raw-output '.assets | .[].browser_download_url' | \
                   grep "\.amd64\.deb")
        else
          DL_URL=$(curl --silent "${API_URL}" | \
                   jq --raw-output '.assets | .[].browser_download_url' | \
                   grep "\.arm.*\.deb")
        fi
      else
        printf "\n\tNo release asset found for this platform ..."
      fi
    fi
  fi
fi

[ "${DL_URL}" ] && {
  if [ "${debian}" ]
  then
    TEMP_DEB="$(mktemp)"
    wget --quiet -O "${TEMP_DEB}" "${DL_URL}"
    sudo dpkg -i "${TEMP_DEB}"
    rm -f "${TEMP_DEB}"
  else
    if [ "${centos}" ] || [ "${fedora}" ]
    then
      sudo rpm --quiet --install ${DL_URL}
    else
      [ "${arch}" ] && sudo pacman -U ${DL_URL}
    fi
  fi
}

@gvenzl
Copy link
Author

gvenzl commented Oct 9, 2022

This looks pretty cool, @doctorfree!

The only thing I'd suggest is making sure that /etc/os-release is executable for the user and if not, throw an error accordingly.
Looking at my machine, the binary is only accessible to root, but not sure whether that's the default or just my env:

[gvenzl@localhost ~]$ ls -al /etc/os-release
lrwxrwxrwx. 1 root root 21 Nov  9  2021 /etc/os-release -> ../usr/lib/os-release
[gvenzl@localhost ~]$ ls -alh /usr/lib/os-release
-rw-r--r-- 1 root root 333 Nov  9  2021 /usr/lib/os-release

@doctorfree
Copy link

/etc/os-release only needs to be readable, not executable, by the user. I believe all Linux distributions set permissions on this as 644 making it readable by all. But, to be sure, a test that /etc/os-release exists and is readable by the user could be performed along with an error if the test fails. Thanks!

@gvenzl
Copy link
Author

gvenzl commented Oct 9, 2022

Hi @doctorfree,

You are right, somehow I expected it to be a binary because there is a man page for it.
Looking at it, it indeed is only a text file with some variables.

Yeah, nice error messages is always a bonus for the end user :)

@Binly42
Copy link

Binly42 commented Nov 27, 2022

for multiple assets, might try:

curl --remote-name-all --location  $( \
    curl -s https://api.github.com/repos/jedisct1/minisign/releases/latest \
    | grep "browser_download_url.*\linux.*" \
    | cut -d : -f 2,3 \
    | tr -d \" )

@gvenzl
Copy link
Author

gvenzl commented Nov 27, 2022

Awesome, thanks @Binly42!

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