Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support fetching latest SNAPSHOT artifacts #284

Merged
merged 1 commit into from Jan 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 45 additions & 0 deletions lib/puppet/functions/archive/artifactory_latest_url.rb
@@ -0,0 +1,45 @@
require 'json'
require 'puppet_x/bodeco/util'

Puppet::Functions.create_function(:'archive::artifactory_latest_url') do
dispatch :artifactory_latest_url do
param 'Variant[Stdlib::HTTPUrl, Stdlib::HTTPSUrl]', :url
param 'Hash', :maven_data
end

def artifactory_latest_url(url, maven_data)
# Turn provided artifactory URL into the fileinfo API endpoint of the parent directory
uri = URI(url.sub('/artifactory/', '/artifactory/api/storage/')[%r{^(.*)/.*$}, 1])

response = PuppetX::Bodeco::Util.content(uri)
content = JSON.parse(response)

uris = if maven_data['classifier']
content['children'].select do |child|
child['uri'] =~ %r{^/#{maven_data['module']}-#{maven_data['base_rev']}-(SNAPSHOT|(?:(?:[0-9]{8}.[0-9]{6})-(?:[0-9]+)))-#{maven_data['classifier']}\.#{maven_data['ext']}$} && !child['folder']
end
else
content['children'].select do |child|
child['uri'] =~ %r{^/#{maven_data['module']}-#{maven_data['base_rev']}-(SNAPSHOT|(?:(?:[0-9]{8}.[0-9]{6})-(?:[0-9]+)))\.#{maven_data['ext']}$} && !child['folder']
end
end

raise("Couldn't find any Artifactory artifacts") if uris.empty?

latest = uris.sort_by { |x| x['uri'] }.last['uri']
Puppet.debug("Latest artifact found for #{url} was #{latest}")

# Now GET the fileinfo endpoint of the resolved latest version file
uri = URI("#{content['uri']}#{latest}")
response = PuppetX::Bodeco::Util.content(uri)
content = JSON.parse(response)

url = content['downloadUri']
sha1 = content['checksums'] && content['checksums']['sha1']

{
'url' => url,
'sha1' => sha1
}
end
end
30 changes: 30 additions & 0 deletions lib/puppet/functions/archive/parse_artifactory_url.rb
@@ -0,0 +1,30 @@
# A function to parse an Artifactory maven 2 repository URL
Puppet::Functions.create_function(:'archive::parse_artifactory_url') do
dispatch :parse_artifactory_url do
param 'Variant[Stdlib::HTTPUrl, Stdlib::HTTPSUrl]', :url
end

def parse_artifactory_url(url)
# Regex is for the 'maven-2-default Repository Layout'
matchdata = url.match(%r{
(?<base_url>.*/artifactory)
/
(?<repository>[^/]+)
/
(?<org_path>.+?)
/
(?<module>[^/]+)
/
(?<base_rev>[^/]+?)
(?:-(?<folder_iteg_rev>SNAPSHOT))?
/
\k<module>-\k<base_rev>
(?:-(?<file_iteg_rev>SNAPSHOT|(?:(?:[0-9]{8}.[0-9]{6})-(?:[0-9]+))))?
(?:-(?<classifier>[^/]+?))?
\.
(?<ext>(?:(?!\d))[^\-/]+|7z)
}x)
return nil unless matchdata
Hash[matchdata.names.zip(matchdata.captures)]
end
end
25 changes: 22 additions & 3 deletions manifests/artifactory.pp
Expand Up @@ -72,24 +72,43 @@
}

if $url {
$file_url = $url
$sha1_url = regsubst($url, '/artifactory/', '/artifactory/api/storage/')
$maven2_data = archive::parse_artifactory_url($url)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if parse_artifactory_url fails to parse the url, it returns nil

if $maven2_data and $maven2_data['folder_iteg_rev'] == 'SNAPSHOT'{
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so if maven2_data is nil, the new code won't be run.

# URL represents a SNAPSHOT version. eg 'http://artifactory.example.com/artifactory/repo/com/example/artifact/0.0.1-SNAPSHOT/artifact-0.0.1-SNAPSHOT.zip'
# Only Artifactory Pro lets you download this directly but the corresponding fileinfo endpoint (where the sha1 checksum is published) doesn't exist.
# This means we can't use the artifactory_sha1 function

$latest_url_data = archive::artifactory_latest_url($url, $maven2_data)

$file_url = $latest_url_data['url']
$sha1 = $latest_url_data['sha1']
} else {
$file_url = $url
$sha1_url = regsubst($url, '/artifactory/', '/artifactory/api/storage/')
$sha1 = undef
}
} elsif $server and $port and $url_path {
warning('archive::artifactory attribute: server, port, url_path are deprecated')
$art_url = "http://${server}:${port}/artifactory"
$file_url = "${art_url}/${url_path}"
$sha1_url = "${art_url}/api/storage/${url_path}"
$sha1 = undef
} else {
fail('Please provide fully qualified url path for artifactory file.')
}

if $sha1 {
$_sha1 = $sha1
} else {
$_sha1 = artifactory_sha1($sha1_url)
}
archive { $file_path:
ensure => $ensure,
path => $file_path,
extract => $extract,
extract_path => $extract_path,
source => $file_url,
checksum => artifactory_sha1($sha1_url),
checksum => $_sha1,
checksum_type => 'sha1',
creates => $creates,
cleanup => $cleanup,
Expand Down
81 changes: 81 additions & 0 deletions spec/functions/parse_artifactory_url_spec.rb
@@ -0,0 +1,81 @@
require 'spec_helper'

describe 'archive::parse_artifactory_url' do
it { is_expected.not_to eq(nil) }
it { is_expected.to run.with_params.and_raise_error(ArgumentError) }
it { is_expected.to run.with_params('not_a_url').and_raise_error(ArgumentError) }

context 'releases' do
it do
is_expected.to run.with_params('https://repo.jfrog.org/artifactory/repo1-cache/maven-proxy/maven-proxy-webapp/0.2/maven-proxy-webapp-0.2.war').and_return(
'base_url' => 'https://repo.jfrog.org/artifactory',
'repository' => 'repo1-cache',
'org_path' => 'maven-proxy',
'module' => 'maven-proxy-webapp',
'base_rev' => '0.2',
'folder_iteg_rev' => nil,
'file_iteg_rev' => nil,
'classifier' => nil,
'ext' => 'war'
)
end
context 'with classifier' do
it do
is_expected.to run.with_params('https://repo.jfrog.org/artifactory/repo1-cache/maven-proxy/maven-proxy-standalone/0.2/maven-proxy-standalone-0.2-app.jar').and_return(
'base_url' => 'https://repo.jfrog.org/artifactory',
'repository' => 'repo1-cache',
'org_path' => 'maven-proxy',
'module' => 'maven-proxy-standalone',
'base_rev' => '0.2',
'folder_iteg_rev' => nil,
'file_iteg_rev' => nil,
'classifier' => 'app',
'ext' => 'jar'
)
end
end
end
context 'SNAPSHOTs' do
it do
is_expected.to run.with_params('https://repo.jfrog.org/artifactory/java.net-cache/com/sun/grizzly/grizzly-framework/2.0.0-SNAPSHOT/grizzly-framework-2.0.0-SNAPSHOT.jar').and_return(
'base_url' => 'https://repo.jfrog.org/artifactory',
'repository' => 'java.net-cache',
'org_path' => 'com/sun/grizzly',
'module' => 'grizzly-framework',
'base_rev' => '2.0.0',
'folder_iteg_rev' => 'SNAPSHOT',
'file_iteg_rev' => 'SNAPSHOT',
'classifier' => nil,
'ext' => 'jar'
)
end
context 'with classifiers' do
it do
is_expected.to run.with_params('https://repo.jfrog.org/artifactory/java.net-cache/com/sun/grizzly/grizzly-framework/2.0.0-SNAPSHOT/grizzly-framework-2.0.0-SNAPSHOT-javadoc.jar').and_return(
'base_url' => 'https://repo.jfrog.org/artifactory',
'repository' => 'java.net-cache',
'org_path' => 'com/sun/grizzly',
'module' => 'grizzly-framework',
'base_rev' => '2.0.0',
'folder_iteg_rev' => 'SNAPSHOT',
'file_iteg_rev' => 'SNAPSHOT',
'classifier' => 'javadoc',
'ext' => 'jar'
)
end
it do
is_expected.to run.with_params('https://repo.jfrog.org/artifactory/java.net-cache/com/sun/grizzly/grizzly-framework/2.0.0-SNAPSHOT/grizzly-framework-2.0.0-SNAPSHOT-tests.jar').and_return(
'base_url' => 'https://repo.jfrog.org/artifactory',
'repository' => 'java.net-cache',
'org_path' => 'com/sun/grizzly',
'module' => 'grizzly-framework',
'base_rev' => '2.0.0',
'folder_iteg_rev' => 'SNAPSHOT',
'file_iteg_rev' => 'SNAPSHOT',
'classifier' => 'tests',
'ext' => 'jar'
)
end
end
end
end