-
-
Save lukechilds/a83e1d7127b78fef38c2914c4ececc3c to your computer and use it in GitHub Desktop.
get_latest_release() { | |
curl --silent "https://api.github.com/repos/$1/releases/latest" | # Get latest release from GitHub api | |
grep '"tag_name":' | # Get tag line | |
sed -E 's/.*"([^"]+)".*/\1/' # Pluck JSON value | |
} | |
# Usage | |
# $ get_latest_release "creationix/nvm" | |
# v0.31.4 |
git ls-remote --refs --sort="version:refname" --tags $repo | cut -d/ -f3-|tail -n1
Must say I ❤️ the github community!
There are always people who takes the challenge to make something better, and shares their findings!
Keep up the great work everyone!
In Fish
you can use string
manipulation that is native, so no other dependencies than curl
:
function get_latest_release_version \
--argument-names user_repo
curl \
--silent \
"https://api.github.com/repos/$user_repo/releases/latest" \
| string match --regex '"tag_name": "\K.*?(?=")'
end
Usage:
❯ get_latest_release_version "rafaelrinaldi/pure"
v3.0.0
Why not use jq?
curl --silent "https://api.github.com/repos/$1/releases/latest" | jq -r .tag_name
Example to get highest version, not just latest - because an LTS bugfix 1.2.3 could be released after a new major 3.x version
curl https://api.github.com/repos/mautic/mautic/releases -s | jq -r .[].tag_name | grep '^[0-9]\.[0-9]*\.[0-9]*$' | sort -nr | head -n
1
or find latest version for a specific major version:
curl https://api.github.com/repos/mautic/mautic/releases -s | jq -r .[].tag_name | grep '^2\.[0-9]*\.[0-9]*$' -m1
curl https://api.github.com/repos/mautic/mautic/releases -s | jq -r .[].tag_name | grep '^3\.[0-9]*\.[0-9]*$' -m1
Hi,
I made a version without sed, only using grep.
Maybe it's useful...
curl --silent "https://api.github.com/repos/$1/releases/latest" | grep -Po '"tag_name": "\K.*?(?=")'
Thanks, for sharing the great idea!
Thanks!
oneliner to get link to the source archive of latest release
curl -s https://github.com/USER/REPO/releases |
grep -m1 -Eo "archive/refs/tags/[^/]+\.tar\.gz" |
xargs printf "https://github.com/USER/REPO/%s"
command to clone the source of latest release to the current folder w/o downloading archive to local disk
ghRepoCloneLatestRelease ()
{
[[ ${1} =~ / ]] &&
wget -qO- https://github.com/${1}/$(curl -s https://github.com/${1}/releases |
grep -m1 -Eo "archive/refs/tags/[^/]+\.tar\.gz") |
tar --strip-components=1 -xzv >/dev/null
}
usage: ghRepoCloneLatestRelease user/repo
@juliy V. Chirkov Thanks a lot!
@Ishidres, you're welcome 💁♀️
$ get_latest_release "ipfs/go-ipfs"
v0.8.0
nice. Thanks a lot.
@juliyvchirkov hi, How can i get the all latest release (including windows or linux etc.) and download it to a folder?
i mean i want to write a script to check releases,if they does not exist or they are older, my script will download update it; and if they are not change, not download?
curl -s https://api.github.com/repos/user/reop/releases/latest | /root/jq-linux64 --raw-output '.assets[] | .browser_download_url' | xargs wget
If you don't want to get just the last release, but all releases with pagination, try this. It's very ugly, I hope somebody can simplify it with awk
or something 😄
next_url="https://api.github.com/repos/Versent/saml2aws/releases"
while [ -n "$next_url" ] ; do
out="$(curl -ifsSL "$next_url")" ; echo "$out" | awk -F '"' '/"tag_name":/{print $4}' | sed -e 's/^v//'
next_url="$(echo "$out" | grep '^link:' \
| sed -e 's/link: //; s/, /\n/g; s/[<>]//g; s/; rel/ rel/g; s/\(https:\/\/[^ ]\+\) rel="\([a-z]\+\)"/\2 \1/g' \
| awk '/next / { print $2}')"
done
If you do use pagination, you might prefer to use the /tags
API endpoint. The data returned is about 100x smaller than /releases
, and for the most part the tag name and release names are the same. Same code here, just a different URI, and use "name":
instead of "tag_name":
above.
Anyone have a GraphQL query for this?
I've used a couple of the above snippets/tools for the initial download of the GitHub CLI, but with the GitHub CLI, you can use gh release download
to download releases from a specific tag, or if you don't supply a tag at all it will use the latest release (and no, latest
as the tag criteria doesn't work unless it actually exists in the repository).
https://cli.github.com/manual/gh_release_download
My favorite practical example might be using gh
to download the latest version of itself. I also learned a new trick for Debian/Ubuntu at least. Since uname -a
shows x86_64
on 64 bit installs I've often struggled with how to detect 32/64 bit and use the correct xxx_linux_amd64.deb
where since it is a deb file we can pretty safely assume we are installing on Linux, but for a .tar.gz
it might be for Solaris or BSD or Linux, so we really only care about the arch.
You can see I don't supply a tag before or after the repo, and I don't quote the *
otherwise it triggers the shell to try and parse it.
gh release download -D /tmp -R cli/cli --pattern *$(dpkg --print-architecture).deb
sudo apt install /tmp/gh_*
For PowerShell/Windows users, a better approach:
((Invoke-WebRequest -Uri https://api.github.com/repos/USER/REPO/releases/latest).Content | ConvertFrom-Json).tag_name
+1 for @spoelstraethan's suggestion! gh
is easy to use & makes downloading the latest release asset an absolute breeze.
Would suggest using that instead of reinventing the wheel & using hacky Shell scripts on any day! And the best part it's available on Homebrew & on Windows so no worries about cross-platform support.
Indeed gh
is easier to use with no work-around, but I found this gist is useful for lightweight purposes such as Docker and CIs. Thanks!
Hi, I made a version without sed, only using grep. Maybe its useful...
curl --silent "https://api.github.com/repos/$1/releases/latest" | grep -Po '"tag_name": "\K.*?(?=")'
Thanks, for sharing the great idea! 👍
In MacOS, the built-in grep
command has not -P
option.
Another mostly reusable one if you just want the latest deb
owner_repo='igniterealtime/Spark'; latest_version_url="$(curl -s https://api.github.com/repos/$owner_repo/releases/latest | grep "browser_download_url.*deb" | cut -d : -f 2,3 | tr -d \")"; echo $latest_version_url; basename $latest_version_url ; wget --content-disposition $latest_version_url
Example:
❯ owner_repo='igniterealtime/Spark'; latest_version_url="$(curl -s https://api.github.com/repos/$owner_repo/releases/latest | grep "browser_download_url.*deb" | cut -d : -f 2,3 | tr -d \")"; echo $latest_version_url; basename $latest_version_url ; wget -q --content-disposition $latest_version_url
https://github.com/igniterealtime/Spark/releases/download/v3.0.0-beta/spark_3_0_0-beta.deb
spark_3_0_0-beta.deb
~ took 1m46s at 20:14:43
❯
Example Link: https://github.com/valinet/ExplorerPatcher/releases/latest/download/ep_setup.exe
Replace "ep_setup.exe" with whatever object name you want.
Probably not Pythonic but Python way:
import requests url = 'https://github.com/roundcube/roundcubemail/releases/latest' r = requests.get(url) version = r.url.split('/')[-1] print(version)Source: https://gist.github.com/zeldor/604a7817f9d142e908335e041ece0718
Made into a function and returns empty for the ones without it.
def get_github_latest_release(repo_path):
import requests
url = f"https://github.com/{repo_path}/releases/latest"
r = requests.get(url, headers={"Content-Type": "application/vnd.github.v3+json"})
release = r.url.split("/")[-1]
if release in ["releases", "latest"]:
release = ""
return release
works nicely for ones with releases
github_repos = [
"https://github.com/OpenVPN/openvpn",
"https://github.com/atom/atom",
"https://github.com/eneshecan/whatsapp-for-linux",
"https://github.com/igniterealtime/Openfire",
"https://github.com/igniterealtime/Spark",
"https://github.com/jitsi/jitsi-meet",
"https://github.com/jitsi/jitsi-meet-prosody",
"https://github.com/jitsi/jitsi-meet-turnserver",
"https://github.com/jitsi/jitsi-meet-web-config",
"https://github.com/jitsi/jitsi-videobridge2",
"https://github.com/mumble-voip/mumble",
"https://github.com/pjsip/pjproject/",
"https://github.com/pydio/pydio-core",
"https://github.com/signalapp/Signal-Desktop",
"https://github.com/sleuthkit/autopsy",
"https://github.com/sleuthkit/sleuthkit",
"https://github.com/ultravnc/ultravnc",
]
def get_repo_path(link):
return link.replace("https://github.com/", "").strip().rstrip("/")
def get_repo_pkg(repo):
return repo.split("/")[-1]
def get_repos_dict_from_urls(urls):
packages = {}
for repo in github_repos:
pkg_name = get_repo_pkg(get_repo_path(repo))
pkg_path = get_repo_path(repo)
packages[pkg_name] = {
"name": pkg_name,
"repo_path": pkg_path,
"url": repo,
"latest_release": get_github_latest_release(pkg_path),
}
return packages
packages = get_repos_dict_from_urls(github_repos)
pprint(packages)
Result:
{'Openfire': {'latest_release': 'v4.7.1',
'name': 'Openfire',
'repo_path': 'igniterealtime/Openfire',
'url': 'https://github.com/igniterealtime/Openfire'},
'Signal-Desktop': {'latest_release': 'v5.45.0',
'name': 'Signal-Desktop',
'repo_path': 'signalapp/Signal-Desktop',
'url': 'https://github.com/signalapp/Signal-Desktop'},
'Spark': {'latest_release': 'v3.0.0-beta',
'name': 'Spark',
'repo_path': 'igniterealtime/Spark',
'url': 'https://github.com/igniterealtime/Spark'},
'atom': {'latest_release': 'v1.60.0',
'name': 'atom',
'repo_path': 'atom/atom',
'url': 'https://github.com/atom/atom'},
'autopsy': {'latest_release': 'autopsy-4.19.3',
'name': 'autopsy',
'repo_path': 'sleuthkit/autopsy',
'url': 'https://github.com/sleuthkit/autopsy'},
'jitsi-meet': {'latest_release': 'jitsi-meet_7287',
'name': 'jitsi-meet',
'repo_path': 'jitsi/jitsi-meet',
'url': 'https://github.com/jitsi/jitsi-meet'},
'jitsi-meet-prosody': {'latest_release': '',
'name': 'jitsi-meet-prosody',
'repo_path': 'jitsi/jitsi-meet-prosody',
'url': 'https://github.com/jitsi/jitsi-meet-prosody'},
'jitsi-meet-turnserver': {'latest_release': '',
'name': 'jitsi-meet-turnserver',
'repo_path': 'jitsi/jitsi-meet-turnserver',
'url': 'https://github.com/jitsi/jitsi-meet-turnserver'},
'jitsi-meet-web-config': {'latest_release': '',
'name': 'jitsi-meet-web-config',
'repo_path': 'jitsi/jitsi-meet-web-config',
'url': 'https://github.com/jitsi/jitsi-meet-web-config'},
'jitsi-videobridge2': {'latest_release': '',
'name': 'jitsi-videobridge2',
'repo_path': 'jitsi/jitsi-videobridge2',
'url': 'https://github.com/jitsi/jitsi-videobridge2'},
'mumble': {'latest_release': 'v1.4.230',
'name': 'mumble',
'repo_path': 'mumble-voip/mumble',
'url': 'https://github.com/mumble-voip/mumble'},
'openvpn': {'latest_release': '',
'name': 'openvpn',
'repo_path': 'OpenVPN/openvpn',
'url': 'https://github.com/OpenVPN/openvpn'},
'pjproject': {'latest_release': '2.12.1',
'name': 'pjproject',
'repo_path': 'pjsip/pjproject',
'url': 'https://github.com/pjsip/pjproject/'},
'pydio-core': {'latest_release': '',
'name': 'pydio-core',
'repo_path': 'pydio/pydio-core',
'url': 'https://github.com/pydio/pydio-core'},
'sleuthkit': {'latest_release': 'sleuthkit-4.11.1',
'name': 'sleuthkit',
'repo_path': 'sleuthkit/sleuthkit',
'url': 'https://github.com/sleuthkit/sleuthkit'},
'ultravnc': {'latest_release': '',
'name': 'ultravnc',
'repo_path': 'ultravnc/ultravnc',
'url': 'https://github.com/ultravnc/ultravnc'},
'whatsapp-for-linux': {'latest_release': 'v1.4.3',
'name': 'whatsapp-for-linux',
'repo_path': 'eneshecan/whatsapp-for-linux',
'url': 'https://github.com/eneshecan/whatsapp-for-linux'}}
owner_repo='igniterealtime/Spark'; latest_version_url="$(curl -s https://api.github.com/repos/$owner_repo/releases/latest | grep "browser_download_url.*deb" | cut -d : -f 2,3 | tr -d ")"; echo $latest_version_url; basename $latest_version_url ; wget --content-disposition $latest_version_url
Thanks a lot! Although it's possible to just use curl instead of wget:
owner_repo='owner/name'; latest_version_url="$(curl -s https://api.github.com/repos/$owner_repo/releases/latest| grep "browser_download_url.*extension" | cut -d : -f 2,3 | tr -d \")"; echo $latest_version_url; basename $latest_version_url ; curl -X GET $latest_version_url -LO
or -Lo name.extension
owner_repo='igniterealtime/Spark'; latest_version_url="$(curl -s https://api.github.com/repos/$owner_repo/releases/latest | grep "browser_download_url.*deb" | cut -d : -f 2,3 | tr -d ")"; echo $latest_version_url; basename $latest_version_url ; wget --content-disposition $latest_version_url
Thanks a lot! Although it's possible to just use curl instead of wget:
owner_repo='owner/name'; latest_version_url="$(curl -s https://api.github.com/repos/$owner_repo/releases/latest| grep "browser_download_url.*extensions" | cut -d : -f 2,3 | tr -d \")"; echo $latest_version_url; basename $latest_version_url ; curl -X GET $latest_version_url -LO
or -Lo name.extension
Awesome thanks for sharing. That is cool always wondered how to do that in curl but never bothered to look. Appreciate the share and explanation.
With the last update, the above breaks for me. I'm now using this:
latest_version_raw="$(curl -s https://api.github.com/repos/$owner_repo/releases | grep -m 1 "html_url" | rev | cut - d/ -f1 | rev )"
latest_version="${latest_version_raw%??}" # remove last 2 characters
Here's an example with wget & jq:
REPO="..."
VERSION=$(wget -q -O- https://api.github.com/repos/${REPO}/releases/latest | jq -r '.name')
Here's an example with wget & jq:
REPO="..." VERSION=$(wget -q -O- https://api.github.com/repos/${REPO}/releases/latest | jq -r '.name')
that works great! but if prefer tag name instead of release name, use:
.tag_name
for how todo this on GitLab site, see my gist here:
https://gist.github.com/roelds/b2cd9cc2ba6c7887ddaf6bde2ef7ef50
One-liner using only curl + grep:
curl --silent "https://api.github.com/repos/${REPO}/releases/latest" | grep -Po "(?<=\"tag_name\": \").*(?=\")"
For the gh-cli inclined:
gh release list --exclude-pre-releases --json tagName,isLatest --jq '.[] | select(.isLatest) | .tagName'
Nice! This is the one that works best for me (I prefer not depending on
jq
and thecurl <url>/releases/latest
based answers only yield<url>/releases
but not the tag - maybe because I didn't explicitly create releases?).Anyway, just to make it even a little bit easier to use:
You may also want to add another
| grep
or| sed
to the pipe to filter for desired tagname patterns (e.g. exclude prereleases).