Puppet Function: github_release

Defined in:
lib/puppet/parser/functions/github_release.rb
Function type:
Ruby 3.x API

Overview

github_release()Any

Fetch a download URL based on Github release informations.

Expects a hash with the following keys:

  • author: Github Author

  • repository: Github repository

  • release: Release to download (defaults to “latest”)

  • asset: Look for an asset of the release instead of a zip- or tarball

    (defaults to true)
    
  • use_zip: Use a zip- instead of a tarball (defaults to false)

  • asset_filepattern: A regular expression to search in the asset filenames

    (defaults to .* (everything))
    
  • asset_contenttype: A regular expression to match against the content types

    in the assets (defaults to .* (everything))
    
  • asset_fallback: If an asset can not be found, use a zip- or tarball instead

    If this is false, an error is raised instead. (defaults to
    true)
    
  • is_tag: The release specified is the name of a tag, not a release (defaults

    to false)
    
  • use_auth: Use authenticated requests, for example to use a bigger rate limit

  • username: GitHub Username

  • password: GitHub password or Authentication token

Returns:

  • (Any)


2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/puppet/parser/functions/github_release.rb', line 2

newfunction(:github_release, :type => :rvalue, :doc => <<-EOS
Fetch a download URL based on Github release informations.

Expects a hash with the following keys:

* author: Github Author 
* repository: Github repository
* release: Release to download (defaults to "latest")
* asset: Look for an asset of the release instead of a zip- or tarball
       (defaults to true)
* use_zip: Use a zip- instead of a tarball (defaults to false)
* asset_filepattern: A regular expression to search in the asset filenames
                   (defaults to .* (everything)) 
* asset_contenttype: A regular expression to match against the content types
                   in the assets (defaults to .* (everything))
* asset_fallback: If an asset can not be found, use a zip- or tarball instead
                If this is false, an error is raised instead. (defaults to
                true)
* is_tag: The release specified is the name of a tag, not a release (defaults
          to false)
* use_auth: Use authenticated requests, for example to use a bigger rate limit
* username: GitHub Username 
* password: GitHub password or Authentication token
EOS
) do |args|

  # Sanity check

  raise(
      Puppet::ParseError,
      'github_release(): Wrong number of arguments'
  ) unless args.size == 1

  # Convert hash keys to symbols

  args[0] = args[0].inject({}) {
      |memo, (k, v)| memo[k.to_sym] = v; memo
  }

  raise(
      Puppet::ParseError,
      'github_release(): No author given'
  ) unless args[0].has_key? :author

  raise(
      Puppet::ParseError,
      'github_release(): No repository given'
  ) unless args[0].has_key? :repository

  debug('Setting defaults')

  arguments = {
      :release => 'latest',
      :use_zip => false,
      :asset_filepattern => '.*',
      :asset_contenttype => '.*',
      :asset_fallback => true,
      :is_tag => false,
      :use_auth => false,
      :username => '',
      :password => ''
  }.merge(args[0])

  filepattern_regexp = Regexp.new(
      arguments[:asset_filepattern],
      Regexp::IGNORECASE
  )

  contenttype_regexp = Regexp.new(
      arguments[:asset_contenttype],
      Regexp::IGNORECASE
  )

  # Build up Github URL

  tag_part = ''

  if arguments[:is_tag]
    tag_part = 'tags/'
  end

  url = sprintf(
      '%s/%s/%s/releases/%s%s',
      'https://api.github.com/repos',
      arguments[:author],
      arguments[:repository],
      tag_part,
      arguments[:release]
  )

  debug(
      sprintf(
          'Loading release information from %s',
          url
      )
  )

  # Download JSON release info from Github

  download_url = ''
  release_info_json = ''

  begin

    release_info_json = function_fetch_from_url(
        [
            {
                :url => url,
                :use_auth => arguments[:use_auth],
                :username => arguments[:username],
                :password => arguments[:password]
            }
        ])

  rescue Net::HTTPServerException => e

    if e.response.code == '404'
      # This repository has no releases

      if arguments[:asset] and not arguments[:asset_fallback]
        raise(
            Puppet::ParseError,
            'Can not find a valid download URL for the release.'
        )
      end

      # Build the zip/tarball URL yourself

      warning('No release information found. Building URL myself.')

      tag = arguments[:release]

      if tag == 'latest'
        # Rework "latest" to "master"
        tag = 'master'
      end

      suffix = '.tar.gz'

      if arguments[:use_zip]
        suffix = '.zip'
      end

      download_url = sprintf(
          '%s/%s/%s/archive/%s%s',
          'https://github.com',
          arguments[:author],
          arguments[:repository],
          tag,
          suffix
      )
    else
      raise e
    end

  end

  if download_url == ''
    # Read in release info from JSON file

    debug('Parsing release info')

    release_info = PSON::load(release_info_json)

    if arguments[:asset]
      debug('Checking assets')
      release_info['assets'].each do |asset|
        debug(sprintf('Checking asset %s', asset['name']))
        if download_url == ''
          if filepattern_regexp.match(asset['name']) and
              contenttype_regexp.match(asset['content_type']) do
                download_url = asset['browser_download_url']
              end
          end
        end
      end
    end

    if !arguments[:asset] or
        (download_url == '' and arguments[:asset_fallback])
      if arguments[:use_zip]
        debug('Setting Zipball URL')
        download_url = release_info['zipball_url']
      else
        debug('Setting Tarball URL')
        download_url = release_info['tarball_url']
      end
      unless download_url == ''
        download_url = function_fetch_from_url(
            [
                {
                    :url => download_url,
                    :use_auth => arguments[:use_auth],
                    :username => arguments[:username],
                    :password => arguments[:password],
                    :ignore_redirect => true
                }
            ]
        )
      end
    end

    if download_url == ''
      raise(
          Puppet::ParseError,
          'Can not find a valid download URL for the release.'
      )
    end
  end

  debug(sprintf('Download URL is %s', download_url))

  download_url

end