Ansible - Download latest release binary from Github repo
Asked Answered
Y

8

21

With Ansible please advise how i could download the latest release binary from Github repository. As per my current understanding the steps would be: a. get URL of latest release b. download the release

For a. I have something like which does not provide the actual release (ex. v0.11.53):

 - name: get latest Gogs release
  local_action:
    module: uri
    url: https://github.com/gogits/gogs/releases/latest
    method: GET
    follow_redirects: no
    status_code: 301
    register: release_url

For b. I have the below which works but needs constant updating. Instead of version i would need a variable set in a.:

- name: download latest
    become: yes
    become-user: "{{gogs_user}}"
    get_url:
     url: https://github.com/gogs/gogs/releases/download/v0.11.53/linux_amd64.tar.gz
    dest: "/home/{{gogs_user}}/linux_amd64.tar.gz"

Thank you!

Yamada answered 21/6, 2018 at 10:54 Comment(0)
R
15

Github has an API to manipulate the release which is documented.

so imagine you want to get the latest release of ansible (which belong to the project ansible) you would

  • call the url https://api.github.com/repos/ansible/ansible/releases/latest
  • get an json structure like this
{
  "url": "https://api.github.com/repos/ansible/ansible/releases/5120666",
  "assets_url": "https://api.github.com/repos/ansible/ansible/releases/5120666/assets",
  "upload_url": "https://uploads.github.com/repos/ansible/ansible/releases/5120666/assets{?name,label}",
  "html_url": "https://github.com/ansible/ansible/releases/tag/v2.2.1.0-0.3.rc3",
  "id": 5120666,
  "node_id": "MDc6UmVsZWFzZTUxMjA2NjY=",
  "tag_name": "v2.2.1.0-0.3.rc3",
  "target_commitish": "devel",
  "name": "THESE ARE NOT OUR OFFICIAL RELEASES",
  ...
  },
  "prerelease": false,
  "created_at": "2017-01-09T16:49:01Z",
  "published_at": "2017-01-10T20:09:37Z",
  "assets": [

  ],
  "tarball_url": "https://api.github.com/repos/ansible/ansible/tarball/v2.2.1.0-0.3.rc3",
  "zipball_url": "https://api.github.com/repos/ansible/ansible/zipball/v2.2.1.0-0.3.rc3",
  "body": "For official tarballs go to https://releases.ansible.com\n"
}
  • get the value of the key tarball_url
  • download the value of the key retrieved just above

In ansible code that would do

- hosts: localhost                                                     
  tasks:                                                               

  - uri:                                                               
      url: https://api.github.com/repos/ansible/ansible/releases/latest
      return_content: true                                             
    register: json_reponse                                             

  - get_url:                                                           
      url: "{{ json_reponse.json.tarball_url }}"                       
      dest: ./ansible-latest.tar.gz       

I let you adapt the proper parameters to answer your question :)

Rao answered 21/6, 2018 at 11:24 Comment(1)
The original question asked about getting the release binary, this answer appears to focus on getting the source tarball. Ansible doesn't release binaries via Github, but the project mentioned in the original question ( github.com/gogs/gogs/releases ) does. To get at these you have to go deeper into the JSON tree, and because projects that do this often to it for multiple platforms you have to also filter for the ones you want as the API will return each binary asset whereas there is only one source tarball.Bug
B
15

I am using the following recipe to download and extract latest watchexec binary for Linux from GitHub releases.

- hosts: localhost                                                     
  tasks:                                                               

  - name: check latest watchexec
    uri:
      url: https://api.github.com/repos/watchexec/watchexec/releases/latest
      return_content: true
    register: watchexec_latest

  - name: "installing watchexec {{ watchexec_latest.json.tag_name }}"
    loop: "{{ watchexec_latest.json.assets }}"
    when: "'x86_64-unknown-linux-musl.tar.xz' in item.name"
    unarchive:
      remote_src: yes
      src: "{{ item.browser_download_url }}"
      dest: "{{ ansible_env.HOME }}/bin/"
      keep_newer: yes
      extra_opts:
      - --strip=1
      - --no-anchored
      - watchexec

tar extra_opts explained here.

This still downloads the binary every time a playbook is called. As an improvement, it might be possible to use set_fact for caching node_id attribute that corresponds to the unpacked file.

Bravo answered 1/7, 2020 at 8:4 Comment(0)
M
11

Another approach is to use ansible github_release module to get the latest tag

example

- name: Get gogs latest tag 
  github_release:
    user: gogs
    repo: gogs
    action: latest_release
  register: gogs_latest 

- name: Grab gogs latest binaries 
  unarchive: 
    src: "https://github.com/gogs/gogs/releases/download/{{ gogs_latest['tag'] }}/gogs_{{ gogs_latest['tag'] | regex_replace('^v','') }}_linux_amd64.zip"
    dest: /usr/local/bin
    remote_src: true 

  • The regex part at the end is for replacing the v at the beginning of the tag since the format now on GitHub for gogs is gogs_0.12.3_linux_armv7.zip and latest tag includes a v
Malvina answered 5/9, 2021 at 20:42 Comment(1)
It returns a Failed and a changed properties as well. What do these two signify?Pachisi
D
2

I got inspired and extended the play. After downloading I add the version number to the binary and link to the program. so I can check on the next run if the version is still up to date. Otherwise it is downloaded and linked again.

- hosts: localhost
  become: false
  vars:
    org: watchexec
    repo: watchexec
    filename: x86_64-unknown-linux-gnu.tar.xz
    version: latest
    project_url: https://api.github.com/repos/{{ org }}/{{ repo }}/releases
  tasks:

  - name: check {{ repo }} version
    uri:
      url: "{{ project_url }}/{{ version }}"
      return_content: true
    register: latest_version

  - name: check if {{ repo }}-{{ version }} already there
    stat:
      path: "{{ ansible_env.HOME }}/.local/bin/{{ repo }}-{{ latest_version.json.tag_name }}"
    register: newestbinary

  - name: download and link to version {{ version }}
    block:
      - name: create tempfile
        tempfile:
          state: directory
          suffix: dwnld
        register: tempfolder_1

      - name: "installing {{ repo }} {{ latest_version.json.tag_name }}"
        # idea from: https://mcmap.net/q/598105/-ansible-download-latest-release-binary-from-github-repo
        loop: "{{ latest_version.json.assets }}"
        when: "filename|string in item.name"
        unarchive:
          remote_src: yes
          src: "{{ item.browser_download_url }}"
          dest: "{{ tempfolder_1.path }}"
          keep_newer: yes
          extra_opts:
          - --strip=1
          - --no-anchored
          - "{{ repo }}"

      - name: command because no mv available
        command: mv "{{ tempfolder_1.path }}/{{ repo }}" "{{ ansible_env.HOME }}/.local/bin/{{ repo }}-{{ latest_version.json.tag_name }}"
        args:
          creates: "{{ ansible_env.HOME }}/.local/bin/{{ repo }}-{{ latest_version.json.tag_name }}"

      - name: "link {{ repo }}-{{ latest_version.json.tag_name }} -> {{ repo }} "
        file:
          src: "{{ ansible_env.HOME }}/.local/bin/{{ repo }}-{{ latest_version.json.tag_name }}"
          dest: "{{ ansible_env.HOME }}/.local/bin/{{ repo }}"
          state: link
          force: yes
    when: not newestbinary.stat.exists
    always:
      - name: delete {{ tempfolder_1.path|default("tempfolder") }}
        file:
          path: "{{ tempfolder_1.path }}"
          state: absent
        when: tempfolder_1.path is defined
        ignore_errors: true

# vim:ft=yaml.ansible:

here is the file on github

Dhahran answered 20/3, 2021 at 15:53 Comment(0)
A
1

Download the latest release with the help of json_query. Note: you might need to_json|from_json as a workaround for this issue.

- name: get the latest release details
  uri:
    url: https://api.github.com/repos/prometheus/node_exporter/releases/latest
    method: GET
  register: node_exp_release
  delegate_to: localhost

- name: set the release facts
  set_fact:
    file_name: "{{ node_exp_latest.name }}"
    download_url: "{{ node_exp_latest.browser_download_url }}"
  vars:
    node_exp_latest: "{{ node_exp_release.json|to_json|from_json|json_query('assets[?ends_with(name,`linux-amd64.tar.gz`)]')|first }}"

- name: download the latest release
  get_url:
    url: "{{ download_url }}"
    dest: /tmp/
Astro answered 23/11, 2021 at 13:1 Comment(2)
Thank you for sharing. Debian doesn't yet have a package for github3.py and I was hesitant to install it via pip. Your solution provided an elegant workaround to using the community.general.github_release Ansible module.Sessler
docs.ansible.com/ansible/latest/collections/community/general/… states, it needs github3.py >= 1.0.0a3 so your comment may not be correct, @JineshChoksiKuching
S
0

I had a similar situation but they didn't use releases, so I found this workaround - it feels more hacky than it should be, but it gets the latest tag and uses that in lieu of releases when they don't exist.

- name: set headers more location
  set_fact: 
    headers_more_location: /srv/headers-more-nginx-module

- name: git clone headers-more-nginx-module
  git:
    repo: https://github.com/openresty/headers-more-nginx-module
    dest: "{{ headers_more_location }}"
    depth: 1
    update: no

- name: get new tags from remote
  command: "git fetch --tags"
  args:
    chdir: "{{ headers_more_location }}"

- name: get latest tag
  command: "git rev-list --tags --max-count=1"
  args:
    chdir: "{{ headers_more_location }}"
  register: tags_rev_list

- name: get latest tag name
  command: "git describe --tags {{ tags_rev_list.stdout }}"
  args:
    chdir: "{{ headers_more_location }}"
  register: latest_tag

- name: checkout the latest version
  command: "git checkout {{ latest_tag.stdout }}"
  args:
    chdir: "{{ headers_more_location }}"
Swarm answered 18/7, 2021 at 18:21 Comment(0)
R
0

Needed to download the latest docker-compose release from github, so came up with the solution below. I know there are other ways to do this, because the latest release content that is returned also contains a direct download link for example. However, I found this solution quite elegant.

- name: Get all docker-compose releases
  uri:
    url: "https://api.github.com/repos/docker/compose/releases/latest"
    return_content: yes
  register: release

- name: Set latest docker-compose release
  set_fact:
    latest_version: "{{ release.json.tag_name }}"

- name: Install docker-compose
  get_url:
    url : "https://github.com/docker/compose/releases/download/{{ latest_version }}/docker-compose-linux-{{ ansible_architecture }}"
    dest: /usr/local/bin/docker-compose
    mode: '755'
Rafael answered 14/1, 2023 at 10:4 Comment(0)
L
0

I found this solution online that does it using only one task and I adapted it to extract the archive directly using the ansible.builtin.unarchive module:

Example with lazygit:

- name: Install lazygit from github
  ansible.builtin.unarchive:
    src: "{{ lookup('url', 'https://api.github.com/repos/jesseduffield/lazygit/releases/latest', split_lines=false) | regex_search('browser_download_url.*(https://(.*?)_Linux_x86_64.tar.gz)', '\\1') | first }}"
    dest: '/home/{{ user }}/.local/bin'
    remote_src: true
    include: 'lazygit'
    mode: 0755

Original task (from the link):

- name: Download the latest cURL distribution
  ansible.builtin.get_url:
    url: "{{ lookup('url', 'https://api.github.com/repos/curl/curl/releases/latest', split_lines=false) | regex_search('browser_download_url.*(https://(.*?).tar.gz)', '\\1') | first }}"
    dest: '{{ build_directory }}/curl-latest.tar.gz'
    owner: root
    group: root
Lentz answered 30/7, 2024 at 15:42 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.