36

I am relatively new to the github api and I am struggling to get the latest tag of a given repo.

Q: Why I need that ?

A: As a QA I am responsible for testing and releasing to LIVE and our team owns around 40 artefacts(repos in github). I want to build a tool which lists the projects which have commits after that latest tag. So that I can manage releases more efficiently.

Coming to the point.

According to Github api to get all tags of a give repo is

GET /repos/:owner/:repo/tags

But this gives the full list of tags the repo has.

Is there an easy way to find the latest tag without iterating through the all available tags from the above api call?

If I have iterate through each tag in order to find the latest tag (based on timestamp of each tag)thats clearly going to be not the efficient way of doing this as the time goes the number of tags will increase and since I want to repeat the same process for at least more than 10 repos.

Any help will be highly appreciated.

Many thanks in advance

  • 1
    You don't need the GitHub API for that; see http://stackoverflow.com/questions/4277773/how-to-get-latest-tag-name. Be aware that only *annotated* tags are associated to a timestamp, though. For simple (i.e. non-annotated) tags, your question remains ambiguous. – jub0bs Mar 17 '15 at 21:25
  • Related: https://stackoverflow.com/questions/18995854/how-can-i-use-github-api-to-get-all-tags-or-releases-for-a-project – Jesse Nickles Oct 08 '22 at 18:51

6 Answers6

21

GitHub doesn't have an API to retrieve the latest tag, as it has for retrieving the latest release. That might be because tags could be arbitrary strings, not necessarily semvers, but it's not really an excuse, since tags have timestamps, and GitHub does sort tags lexicographically when returning them via its Tags API.

Anyway, to get the latest tag, you need to call that API, then sort the tags according to semver rules. Since these rules are non-trivial (see point 11 at that link), it's better to use the semver library (ported for the browser).

const gitHubPath = 'dandv/local-iso-dt';  // example repo
const url = 'https://api.github.com/repos/' + gitHubPath + '/tags';

$.get(url).done(data => {
  const versions = data.sort((v1, v2) => semver.compare(v2.name, v1.name));
  $('#result').html(versions[0].name);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/hippich/bower-semver/master/semver.min.js"></script>
<p>Latest tag: <span id="result"></span></p>
Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
  • 1
    This solves the problem without the requirement of local installation of `git`. And the trick here seems to be doing some web scraping on the **github** tags page. For web scraping, the css selector of these tags is just `.commit-title a`. – Liang Zhang Dec 22 '20 at 14:54
  • GitHub _DOES_ have a GraphQL API for that... see the answer by @bertrand-martel – rü- Mar 13 '21 at 06:10
18

The easiest I found (and usefull for my case where there is no "latest" and I dont want to checkout the branch) was:

curl  "https://api.github.com/repos/certbot/certbot/tags" | jq -r '.[0].name'

This jus prints the "highest" tag-number from the (e.g.) corresponding certbot tags-page (at https://github.com/certbot/certbot/tags)

kudos to https://gist.github.com/lukechilds/a83e1d7127b78fef38c2914c4ececc3c#gistcomment-2649739

MacMartin
  • 2,366
  • 1
  • 24
  • 27
15

You can get the latest release at https://api.github.com/repos/$org/$repo/releases/latest

If you want just the tag name, you can try something like this:

curl https://api.github.com/repos/$org/$repo/releases/latest -s | jq .name -r
Aurora0001
  • 13,139
  • 5
  • 50
  • 53
Mathieu
  • 5,495
  • 2
  • 31
  • 48
  • 3
    This won't work if the repository uses tags for versioning but doesn't use the GitHub system to create releases. A real world example would be a Drupal project that does development on GitHub but releases through drupal.org – Alexander Varwijk Aug 22 '17 at 11:48
  • what do you mean AlexanderVarwijk ? I’m not aware of how you can disable releases in github, do you have an example ? – Mathieu Sep 29 '17 at 18:36
  • 2
    As far as I'm aware you can't disable them either. However, it's very well possible to use GitHub and git tags without actually creating a release on GitHub. – Alexander Varwijk Oct 02 '17 at 06:57
  • how ? do you have an exemple ? – Mathieu Oct 10 '17 at 20:35
  • I can't find one anymore. I thought I had a repo that had tags but reported no releases. :/ – Alexander Varwijk Oct 12 '17 at 09:12
  • 1
    Eg. https://github.com/angular/angular.js/releases - API don't return real releases for this repo, there are just tags – Jurosh Oct 12 '17 at 19:02
  • Incredibly useful, thank you for this, wish I could upvote more than once! – davnicwil Jul 11 '18 at 16:51
  • Another example of a repo that uses tags but not releases is vscode - https://github.com/microsoft/vscode/tags is there but querying the API returns a null set. – luckman212 May 16 '19 at 21:16
8

You could consider, as an alternative to the GitHub API, a simple script mentioned in "Is there a simple way to “git describe” a remote repository?" (source, by svnpenn):

#!/usr/bin/awk -f
BEGIN {
  if (ARGC != 2) {
    print "git-describe-remote.awk https://github.com/stedolan/jq"
    exit
  }
  FS = "[ /^]+"
  while ("git ls-remote " ARGV[1] "| sort -Vk2" | getline) {
    if (!sha)
      sha = substr($0, 1, 7)
    tag = $3
  }
  while ("curl -s " ARGV[1] "/releases/tag/" tag | getline)
    if ($3 ~ "commits")
      com = $2
  printf com ? "%s-%s-g%s\n" : "%s\n", tag, com, sha
}

That does extract the tag (and more), without having to clone the repo.

Note: as commented below by Joels Elf, make sure /usr/bin/awk refers to gawk, not mawk.

Elie G.
  • 1,514
  • 1
  • 22
  • 38
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 1
    Thanks for the script. I am still interested to see whether is there a way to achieve the same using GITHUB API ( As I am planning to build a web tool :) which takes a list of repos from different owners ) – Varun Kumar Rao Ponugoti Mar 19 '15 at 08:54
  • @VarunKumarRaoPonugoti then `GET /repos/:owner/:repo/tags` remains your main option, it seems. – VonC Mar 19 '15 at 09:22
  • This script and the source script don't work for me on both my Mac and Ubuntu 14.04. In Ubuntu I get `/bin/sh: 1: Syntax error: "|" unexpected` – Joels Elf May 31 '16 at 17:52
  • 1
    @JoelsElf Try with the moire recent version of that script at https://github.com/svnpenn/a/blob/d3a1b0bf8b54f949f813687e68e153f208e2a106/git/git-describe-remote.awk – VonC May 31 '16 at 19:02
  • 1
    Thanks for replying! The new script gave the same error so I checked `awk`'s version and found I was using `mawk`. When I installed and used `gawk` instead it worked like a charm! – Joels Elf Jun 01 '16 at 20:35
  • @JoelsElf Well spotted! I have included your comment in the answer for more visibility. – VonC Jun 01 '16 at 20:38
  • It does not always return the latest tag. I tried with this repo: https://github.com/microsoft/vscode and it returned `v1.19.3` which is far from the latest one. Actually it should return `1.39.1` – Elie G. Oct 13 '19 at 02:10
6

Using GraphQL API v4, you can get the last tag by alphabetical or commit date. For instance by commit date (eg the tag that point to the most recent commit) :

{
  repository(owner: "bertrandmartel", name: "caipy-dashboard") {
    refs(refPrefix: "refs/tags/", first: 1, orderBy: {field: TAG_COMMIT_DATE, direction: DESC}) {
      edges {
        node {
          name
          target {
            oid
            ... on Tag {
              message
              commitUrl
              tagger {
                name
                email
                date
              }
            }
          }
        }
      }
    }
  }
}

test it in the explorer

Note that if the tag is a lightweight tag, there will be no taggeror message field. You can also use field: ALPHABETICAL for the last tag in alphabetical order.

If you want to get the last tag that was created (which could be different from the tag that point to the most recent commit, or the last tag in alphabetical order), it's only possible for annotated tag since their creation date is stored and will be available in the tagger field.

To get the last created tag, you would get all the tags and filter the most recent date in data.repository.refs.edges.node.target.tagger.date field in the response of the following request :

{
  repository(owner: "google", name: "gson") {
    refs(refPrefix: "refs/tags/", first: 100, orderBy: {field: TAG_COMMIT_DATE, direction: DESC}) {
      edges {
        node {
          name
          target {
            oid
            ... on Tag {
              commitUrl
              tagger {
                date
              }
            }
          }
        }
      }
    }
  }
}

test it in the explorer

Bertrand Martel
  • 42,756
  • 16
  • 135
  • 159
0

I would suggest something simple using awk from bash

curl https://api.github.com/repos/{organization}/{repository_name}/releases/latest | grep -i "tag_name" | awk -F '"' '{print $4}'

  • curl fetches latest release info
  • grep finds field "tag_name": "1.1.1"
  • awk parses "tag_name": "1.1.1" to just 1.1.1
Slava.In
  • 597
  • 1
  • 9
  • 22