How to determine the latest release on GitHub
Introduction
This post is about programmatically determining the latest version of a GitHub release. We are doing this using shell scripting.
Accessing release data on the command-line
Let’s say you want to determine the latest release of the gohugo.io static site generator. All release information needed can be accessed through the GitHub API. For hugo, it can be queried using the following URL:
https://api.github.com/repos/gohugoio/hugo/releases/latest
The data behind this URL is JSON encoded. When accessing it using a web browser, a handy UI typically allows to fold/unfold sections of it. This way one can determine the interesting sections to be further processed.
On the command-line, a HTTP client such as curl allows to access this information like this:
curl https://api.github.com/repos/gohugoio/hugo/releases/latest 2>/dev/null
All information related to the HTTP data transfer is actually redirected to the
/dev/null
device. It is not needed. The actual data is provided on STDOUT.
Now the JSON data needs to be processed using some JSON parser.
Enter jq
This is, where jq comes in handy. It allows
to access (say: slice, filter, and map) JSON data on the command-line to allow
for further processing using the typical suspects such as sed
, ask
, or
grep
. Let’s find out what the .name
field of the returned data gives us:
curl https://api.github.com/repos/gohugoio/hugo/releases/latest 2>/dev/null \
| jq .name
At the time of writing it is: "v0.80.0"
. Now, let’s assume we want to get rid
of the "
s and the v
. This can easily be done by stripping these characters.
Post-processing
Stripping characters from strings on the command-line can be achieved using
some builtin functions of jq
:
curl https://api.github.com/repos/gohugoio/hugo/releases/latest 2>/dev/null \
| jq -r '.name | ltrimstr("v")'
The -r
switch to jq
requests it to output raw data, resulting in stripping
the quotes from the output.
Now, what remains is what we have been looking for: 0.80.0
Bonus: using it in Ansible playbooks
The following shows an Ansible playbook which
downloads the latest release of
gohugo.io for ARM based systems and
installs it in the /usr/local/bin
directory:
---
- name: Make gohugo available
hosts: all
tasks:
- name: Install needed packages
become: true
apt:
name:
- jq
- curl
state: present
- name: Get hugo latest release version
shell:
cmd: curl https://api.github.com/repos/gohugoio/hugo/releases/latest | jq -r '.name | ltrimstr("v")'
register: hugo_version
- name: Get hugo latest release
get_url:
url: https://github.com/gohugoio/hugo/releases/download/v{{ hugo_version.stdout }}/hugo_{{ hugo_version.stdout }}_Linux-ARM.tar.gz
dest: /tmp/hugo.tar.gz
- name: Unarchive hugo latest release
unarchive:
src: /tmp/hugo.tar.gz
remote_src: true
dest: /usr/local/bin
Sure, this playbook is not perfect. But it should give a good idea of how using
jq
can help to automatize repetitive tasks when combined with
Ansible.