Class: Buildr::MavenCentral

Inherits:
Object show all
Defined in:
lib/buildr/java/publish.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#passwordObject



119
120
121
# File 'lib/buildr/java/publish.rb', line 119

def password
  @password || (raise 'Password not yet specified')
end

#user_agentObject



125
126
127
# File 'lib/buildr/java/publish.rb', line 125

def user_agent
  @user_agent || "Ruby-#{RUBY_VERSION}"
end

#usernameObject



113
114
115
# File 'lib/buildr/java/publish.rb', line 113

def username
  @username || (raise 'Username not yet specified')
end

Class Method Details

.buildr_release(project, profile_name, username, password) ⇒ Object



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
# File 'lib/buildr/java/publish.rb', line 78

def buildr_release(project, profile_name, username, password)
  release_to_url = Buildr.repositories.release_to[:url]
  release_to_username = Buildr.repositories.release_to[:username]
  release_to_password = Buildr.repositories.release_to[:password]

  begin
    Buildr.repositories.release_to[:url] = 'https://oss.sonatype.org/service/local/staging/deploy/maven2'
    Buildr.repositories.release_to[:username] = username
    Buildr.repositories.release_to[:password] = password

    project.task(':package').invoke

    r = MavenCentral.new
    r.username = username
    r.password = password
    r.user_agent = "Buildr-#{Buildr::VERSION}"
    while r.get_staging_repositories(profile_name, false).size != 0
      puts 'Another project currently staging. Waiting for other repository to complete. Please visit the website https://oss.sonatype.org/index.html#stagingRepositories to view the other staging attempts.'
      sleep 1
    end
    puts "Beginning upload to staging repository #{profile_name}"

    project.task(':upload').invoke

    r.release_sole_auto_staging(profile_name)
  ensure
    Buildr.repositories.release_to[:url] = release_to_url
    Buildr.repositories.release_to[:username] = release_to_username
    Buildr.repositories.release_to[:password] = release_to_password
  end
end

.define_publish_tasks(options = {}) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/buildr/java/publish.rb', line 22

def define_publish_tasks(options = {})
  candidate_branches = options[:branches] || %w(master)
  desc 'Publish release on maven central'
  task 'mcrt:publish' do
    project = options[:project] || Buildr.projects[0].root_project
    profile_name = options[:profile_name] || (raise ':profile_name not specified when defining tasks')
    username = options[:username] || (raise ':username name not specified when defining tasks')
    password = options[:password] || ENV['MAVEN_CENTRAL_PASSWORD'] || (raise "Unable to locate environment variable with name 'MAVEN_CENTRAL_PASSWORD'")
    MavenCentral.buildr_release(project, profile_name, username, password)
  end

  desc 'Publish release to maven central iff current HEAD is a tag'
  task 'mcrt:publish_if_tagged' do
    tag = MavenCentral.get_head_tag_if_any
    if tag.nil?
      puts 'Current HEAD is not a tag. Skipping publish step.'
    else
      puts "Current HEAD is a tag: #{tag}"
      if MavenCentral.is_tag_on_candidate_branches?(tag, candidate_branches)
        task('mcrt:publish').invoke
      end
    end
  end
end

.get_head_tag_if_anyObject



47
48
49
50
51
52
53
54
# File 'lib/buildr/java/publish.rb', line 47

def get_head_tag_if_any
  version = `git describe --exact-match --tags 2>&1`
  if 0 == $?.exitstatus && version =~ /^v[0-9]/ && (ENV['TRAVIS_BUILD_ID'].nil? || ENV['TRAVIS_TAG'].to_s != '')
    version.strip
  else
    nil
  end
end

.is_tag_on_branch?(tag, branch) ⇒ Boolean

Returns:

  • (Boolean)


56
57
58
59
60
# File 'lib/buildr/java/publish.rb', line 56

def is_tag_on_branch?(tag, branch)
  output = `git tag --merged #{branch} 2>&1`
  tags = output.split
  tags.include?(tag)
end

.is_tag_on_candidate_branches?(tag, branches) ⇒ Boolean

Returns:

  • (Boolean)


62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/buildr/java/publish.rb', line 62

def is_tag_on_candidate_branches?(tag, branches)
  sh 'git fetch origin'
  branches.each do |branch|
    if is_tag_on_branch?(tag, branch)
      puts "Tag #{tag} is on branch: #{branch}"
      return true
    elsif is_tag_on_branch?(tag, "origin/#{branch}")
      puts "Tag #{tag} is on branch: origin/#{branch}"
      return true
    else
      puts "Tag #{tag} is not on branches: #{branch} or origin/#{branch}"
    end
  end
  false
end

Instance Method Details

#close_repository(repository_id, description) ⇒ Object



174
175
176
177
# File 'lib/buildr/java/publish.rb', line 174

def close_repository(repository_id, description)
  post_request('https://oss.sonatype.org/service/local/staging/bulk/close',
               JSON.pretty_generate('data' => { 'description' => description, 'stagedRepositoryIds' => [repository_id] }))
end

#drop_repository(repository_id, description) ⇒ Object



186
187
188
189
# File 'lib/buildr/java/publish.rb', line 186

def drop_repository(repository_id, description)
  post_request('https://oss.sonatype.org/service/local/staging/bulk/drop',
               JSON.pretty_generate('data' => { 'description' => description, 'stagedRepositoryIds' => [repository_id] }))
end

#get_my_ip_addressesObject



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
# File 'lib/buildr/java/publish.rb', line 141

def get_my_ip_addresses
  addresses = Socket.ip_address_list.collect { |a| a.ip_address.to_s }
  commands = [
    "dig +short myip.opendns.com @resolver1.opendns.com",
    "curl ifconfig.me",
    "curl icanhazip.com",
    "curl ipecho.net/plain",
    "curl ifconfig.co",
    "dig TXT +short o-o.myaddr.l.google.com @ns1.google.com | awk -F'\"' '{ print $2 }'"
  ]
  commands.each do |cmd|
    begin
      addresses << `#{cmd}`.strip
    rescue Exception
      # ignored
    end
  end
  urls = %w[http://www.myexternalip.com/raw https://diagnostic.opendns.com/myip]
  urls.each do |url|
    begin
      addresses << Net::HTTP.get(URI(url)).strip
    rescue Exception
      # ignored
    end
  end
  begin
    addresses << JSON.parse(Net::HTTP.get(URI('https://api.ipify.org?format=json')))['ip']
  rescue Exception
    # ignored
  end
  addresses.sort.uniq
end

#get_staging_repositories(profile_name, ignore_transitioning_repositories = true) ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
# File 'lib/buildr/java/publish.rb', line 129

def get_staging_repositories(profile_name, ignore_transitioning_repositories = true)
  result = get_request('https://oss.sonatype.org/service/local/staging/profile_repositories')
  result = JSON.parse(result)
  result['data'].select do |repo|
    repo['profileName'] == profile_name &&
      repo['userId'] == self.username &&
      repo['userAgent'] == self.user_agent &&
      (!ignore_transitioning_repositories || !repo['transitioning']) &&
      get_my_ip_addresses.any? { |a| a == repo['ipAddress'] }
  end
end

#promote_repository(repository_id, description) ⇒ Object



179
180
181
182
183
184
# File 'lib/buildr/java/publish.rb', line 179

def promote_repository(repository_id, description)
  post_request('https://oss.sonatype.org/service/local/staging/bulk/promote',
               JSON.pretty_generate('data' => { 'autoDropAfterRelease' => true,
                                                'description' => description,
                                                'stagedRepositoryIds' => [repository_id] }))
end

#release_sole_auto_staging(profile_name) ⇒ Object



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
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/buildr/java/publish.rb', line 191

def release_sole_auto_staging(profile_name)
  candidates = get_staging_repositories(profile_name)
  if candidates.empty?
    raise 'Release process unable to find any staging repositories.'
  elsif 1 != candidates.size
    raise 'Release process found multiple staging repositories that could be the release just uploaded. Please visit the website https://oss.sonatype.org/index.html#stagingRepositories and manually complete the release.'
  else
    candidate = candidates[0]
    puts "Requesting close of staging repository #{profile_name}:#{candidate['repositoryId']}"
    begin
      close_repository(candidate['repositoryId'], "Closing repository for #{profile_name}")
    rescue Exception => e
      puts "#{e.class.name}: #{e.message}"
      puts e.backtrace.join("\n")
      raise 'Failed to close repository. It is likely that the release does not conform to Maven Central release requirements. Please visit the website https://oss.sonatype.org/index.html#stagingRepositories and manually complete the release.'
    end
    while get_staging_repositories(profile_name).size == 0
      puts 'Waiting for repository to close...'
      sleep 1
    end
    puts "Requesting promotion of staging repository #{profile_name}:#{candidate['repositoryId']}"
    begin
      promote_repository(candidate['repositoryId'], "Promoting repository for #{profile_name}")
    rescue Exception => e
      puts "#{e.class.name}: #{e.message}"
      puts e.backtrace.join("\n")
      raise 'Failed to promote repository. Please visit the website https://oss.sonatype.org/index.html#stagingRepositories and manually complete the release.'
    end
    repositories = get_staging_repositories(profile_name, false)
    while repositories.size == 1
      puts 'Waiting for repository to be promoted...'
      sleep 1
      if repositories[0]['notifications'] != 0
        raise 'Failed to promote repository. Please visit the website https://oss.sonatype.org/index.html#stagingRepositories and manually complete the release.'
      end
      repositories = get_staging_repositories(profile_name, false)
    end
  end
end