Skip to content
This repository was archived by the owner on Feb 28, 2019. It is now read-only.

Commit 4810c33

Browse files
committed
Add initial release script
1 parent 6f0666b commit 4810c33

File tree

4 files changed

+217
-0
lines changed

4 files changed

+217
-0
lines changed

.travis.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,8 @@ install:
1717
script: buildr package publish_if_tagged
1818
git:
1919
depth: false
20+
env:
21+
global:
22+
- secure: l49Eyu3lZdxFgZYeUEo+nVnLH9wn5p7vDSd1SHyz4JPGOsUCzdQ0Jp/KnnhioOkOFeC0ZaWbrKMO2nxk3/0MRQV4cqJMHwr/owdNr1smscMY3h+HUaPbrScXLgiFwYHb55hqeid8oj+DDPmx+MeJ1IgPilxWI8WwV0lJ/D2l87i0KodJDQHExVcJAGaJQsXFE8E12nGlpvKmAz6fatfZ9XbAKx8npaOpknUMmz1W2kXOsRnLmtce+gpfp8rZHmm2NYbxswZspXfIeaFX6MteafplX1CY4gWQ0WVfGCxkmSH8OI6I8+hDP9fidMje/8qcf3DWjanmRGidvHwf+mAajkaPKJcMXCl54L9kBqvM8g9ccefU5lx8yhtmAlPz2aVr6XCHf51x6cPvTP8Wtevvy68UdlbBPG+mVlHpRVihmDwJzQZZWJ7M8PHIebCmKIA4RIv2wRQ5cla/RK8q+YiABUd75yWDwRH/l06sBO0zujqyaD+XGpOBV/w5S8og3v7lZUBo7AWl5ObDOCNGGEfUgKLiHQHqm0Ry7xrODS7zrUb7+zVwLNncSCSPc7Ei3XgNmr06fYn9AYdo1oiywOcIh55DmfsIMhyqXYvbkfyKsWhkJ26GPAYhWiDL2T7Wq4LWkpfox12p7ski6YiHeUYQbfyHXnpckoJO8Zz9akCI7gs=
23+
- secure: WC+nMM5nl/xSkfhGS7lnN5M4TPduROmA84KlOC1qdBI0AVpaixcTLxNP735Zg+3jyJg5pv458oyaaIeii1A91dKsMiXSBmlIfOd5oYfKue2z3lqBa3Nnz7iOMB9k3Bt3VeXrohAI+14wNTFz4ZrE8Kh4c/js7WtJggNz8g5drZAH0aPa8mirkMBcEiYl7sKr++i679MVagzsDX2GcrR5oNYOFguK+jUJTZpBw382nYDonRDi9zzsGRxFRqyYCMBe+VufRwnuuo0u09jy4WeXWNC8ABHINu/R2rbiNmyOjKV/54VY07Afr+StS5jcSqk+me0MYeTRUKaQ5sQLAhj6JTwQE+RRSISOsgSaQzSzkCExNv8PwaL3UfekxKyVS0aJPVh+NGyoxcpZNVAdIImKc3e0rdFA4WJeOP32NkLU8c2vIXo3sYsTnWfLudaMcXcsb2E5pDC8vcCXjzOKLU2bpmA/KFW+NbI67QobGO+2UEQFCMvgm6nVxzoocNtuR/qjbVkX6H+OW/k/q+x+XMJrNXPW7iHVHXLMEf3/2RULNVXvz1rB9+xlcoztUuatp0+IG7M52MGdDNl/CmkEbPHi3WgxLEOuTaUetRpfQ2g3SpcPVwADrAqeKzkOUhuuIMW24JGbYexmp/RRKKSt2rSUh9fP/fEoP4tCjd/f1Xkzvlc=
24+
- secure: AH3AUCN7Xd9QiBOp25QNqCuZN/cnBjixI6lEl10CXwb/P6tHsix03CzZy8DgB3Ix4/qkU/9iPxykJPLczKduxarqpNvW1j8EE4k3YXu2Gv/ST2zME1115CiT7v4QMVlpMOzsLj5E4U7+UODSlFL92PLlJpA4m0y1ex5+Mi/0wnBkx29vgDpyNi01sSanZwk+YqLzomBNdhVJV+I5Sos2I+O1iNuyyR6n51hKiiptSb2Y1dtjTkO2vNwZjfS1zhEDi8Sf0rI+qs+7gFjtPHjiY2h/r29nKWMefn1o1ik0zDLDeWpB0RF5M7L/D/IT2tfz94DlHN+vnujyyri47FYpbl6Pwl4w8C9/ZH7ib5x7aG9VJ924FZyRYaRDurhIwvHlZ726pSXQu2idib3fL5/2LguYR22WaBbgltqc3Mmrg1hJ7GKl9F8w6vtl1K/Nr1Y6gdpDu8rsqko6AEm5p6UOVnZK56J7eibJJ4tCSzfvyqesatA3uTQc6pozTTRp6VKlT4QH/F6UFrN491VD0B4z2RZyrYwHq8RYQH0CiwGZHJ6iEIF6Ug4ftgsC9AtDPhoar5DxmIm/pA0bUlCoH+MO6NjdSwRCWZt/CJB/Mm/jfNcrjF2xB1T8CrI1NSLpXwVQ+wmE/DkWzMr9YDg8iFvv/ctBi27QJDMLpz0VFmUIJs4=

etc/secrets

0 Bytes
Binary file not shown.

tasks/buildr_artifact_patch.rake

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
raise 'Patch already integrated into buildr code' unless Buildr::VERSION.to_s == '1.5.5'
2+
3+
module Buildr::ActsAsArtifact
4+
def upload_task(upload_to = nil)
5+
upload_to ||= Buildr.repositories.snapshot_to if snapshot? && Buildr.repositories.snapshot_to != nil && Buildr.repositories.snapshot_to[:url] != nil
6+
upload_to ||= Buildr.repositories.release_to
7+
upload_to = { :url => upload_to } unless Hash === upload_to
8+
raise ArgumentError, 'Don\'t know where to upload, perhaps you forgot to set repositories.release_to' unless upload_to[:url]
9+
10+
# Set the upload URI, including mandatory slash (we expect it to be the base directory).
11+
# Username/password may be part of URI, or separate entities.
12+
uri = URI.parse(upload_to[:url].clone)
13+
uri.path = uri.path + '/' unless uri.path[-1] == '/'
14+
to_escape = "!\"\#$%&'()*+,-./:;<=>?@{}|~`'"
15+
uri.user = URI.encode(upload_to[:username], to_escape) if upload_to[:username]
16+
uri.password = URI.encode(upload_to[:password], to_escape) if upload_to[:password]
17+
18+
path = group.gsub('.', '/') + "/#{id}/#{version}/#{upload_name}"
19+
20+
unless task = Buildr.application.lookup(uri+path)
21+
deps = [self]
22+
deps << pom.upload_task(upload_to) if pom && pom != self && classifier.nil?
23+
24+
task = Rake::Task.define_task uri + path => deps do
25+
# Upload artifact relative to base URL, need to create path before uploading.
26+
options = upload_to[:options] || { :permissions => upload_to[:permissions] }
27+
info "Deploying #{to_spec}"
28+
URI.upload uri + path, name, options
29+
if snapshot? && pom != self
30+
maven_metadata = group.gsub('.', '/') + "/#{id}/#{version}/#{MAVEN_METADATA}"
31+
URI.write uri + maven_metadata, maven_metadata_xml, :permissions => upload_to[:permissions]
32+
end
33+
end
34+
end
35+
task
36+
end
37+
end
38+
39+
class URI::HTTP
40+
private
41+
42+
def write_internal(options, &block)
43+
options ||= {}
44+
connect do |http|
45+
trace "Uploading to #{path}"
46+
content = StringIO.new
47+
while chunk = yield(RW_CHUNK_SIZE)
48+
content << chunk
49+
end
50+
headers = { 'Content-MD5' => Digest::MD5.hexdigest(content.string), 'Content-Type' => 'application/octet-stream', 'User-Agent' => "Buildr-#{Buildr::VERSION}" }
51+
request = Net::HTTP::Put.new(request_uri.empty? ? '/' : request_uri, headers)
52+
request.basic_auth URI.decode(self.user), URI.decode(self.password) if self.user
53+
response = nil
54+
with_progress_bar options[:progress], path.split('/').last, content.size do |progress|
55+
request.content_length = content.size
56+
content.rewind
57+
stream = Object.new
58+
class << stream;
59+
self;
60+
end.send :define_method, :read do |*args|
61+
bytes = content.read(*args)
62+
progress << bytes if bytes
63+
bytes
64+
end
65+
request.body_stream = stream
66+
response = http.request(request)
67+
end
68+
69+
case response
70+
when Net::HTTPRedirection
71+
# Try to download from the new URI, handle relative redirects.
72+
trace "Redirected to #{response['Location']}"
73+
content.rewind
74+
return (self + URI.parse(response['location'])).write_internal(options) {|bytes| content.read(bytes)}
75+
when Net::HTTPSuccess
76+
else
77+
raise RuntimeError, "Failed to upload #{self}: #{response.message}"
78+
end
79+
end
80+
end
81+
end

tasks/release.rake

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
WORKSPACE_DIR = File.expand_path(File.dirname(__FILE__) + '/..')
2+
3+
def in_dir(dir)
4+
current = Dir.pwd
5+
begin
6+
Dir.chdir(dir)
7+
yield
8+
ensure
9+
Dir.chdir(current)
10+
end
11+
end
12+
13+
def stage(stage_name, description, options = {})
14+
if ENV['STAGE'].nil? || ENV['STAGE'] == stage_name || options[:always_run]
15+
puts "🚀 Release Stage: #{stage_name} - #{description}"
16+
begin
17+
yield
18+
rescue Exception => e
19+
puts '💣 Error completing stage.'
20+
puts "Fix the error and re-run release process passing: STAGE=#{stage_name}#{ ENV['PREVIOUS_PRODUCT_VERSION'] ? " PREVIOUS_PRODUCT_VERSION=#{ENV['PREVIOUS_PRODUCT_VERSION']}" : ''}#{ ENV['PREVIOUS_PRODUCT_VERSION'] ? " PRODUCT_VERSION=#{ENV['PRODUCT_VERSION']}" : ''}"
21+
raise e
22+
end
23+
ENV['STAGE'] = nil unless options[:always_run]
24+
elsif !ENV['STAGE'].nil?
25+
puts "Skipping Stage: #{stage_name} - #{description}"
26+
end
27+
end
28+
29+
desc 'Perform a release'
30+
task 'perform_release' do
31+
32+
in_dir(WORKSPACE_DIR) do
33+
stage('ExtractVersion', 'Extract the last version from CHANGELOG.md and derive next version unless specified', :always_run => true) do
34+
changelog = IO.read('CHANGELOG.md')
35+
ENV['PREVIOUS_PRODUCT_VERSION'] ||= changelog[/^### \[v(\d+\.\d+)\]/, 1]
36+
37+
next_version = ENV['PRODUCT_VERSION']
38+
unless next_version
39+
version_parts = ENV['PREVIOUS_PRODUCT_VERSION'].split('.')
40+
next_version = "#{version_parts[0]}.#{sprintf('%02d', version_parts[1].to_i + 1)}"
41+
ENV['PRODUCT_VERSION'] = next_version
42+
end
43+
44+
# Also initialize release date if required
45+
ENV['RELEASE_DATE'] ||= Time.now.strftime('%Y-%m-%d')
46+
end
47+
48+
stage('ZapWhite', 'Ensure that zapwhite produces no changes') do
49+
sh 'bundle exec zapwhite'
50+
end
51+
52+
stage('GitClean', 'Ensure there is nothing to commit and the working tree is clean') do
53+
status_output = `git status -s 2>&1`.strip
54+
raise 'Uncommitted changes in git repository. Please commit them prior to release.' if 0 != status_output.size
55+
end
56+
57+
stage('Build', 'Build the project to ensure that the tests pass') do
58+
sh "bundle exec buildr clean package PRODUCT_VERSION=#{ENV['PRODUCT_VERSION']}"
59+
end
60+
61+
stage('PatchChangelog', 'Patch the changelog to update from previous release') do
62+
changelog = IO.read('CHANGELOG.md')
63+
changelog = changelog.gsub("### Unreleased\n", <<HEADER)
64+
### [v#{ENV['PRODUCT_VERSION']}](https://github.com/react4j/react4j-widget/tree/v#{ENV['PRODUCT_VERSION']}) (#{ENV['RELEASE_DATE']})
65+
[Full Changelog](https://github.com/react4j/react4j-widget/compare/v#{ENV['PREVIOUS_PRODUCT_VERSION']}...v#{ENV['PRODUCT_VERSION']})
66+
HEADER
67+
IO.write('CHANGELOG.md', changelog)
68+
69+
sh 'git reset 2>&1 1> /dev/null'
70+
sh 'git add CHANGELOG.md'
71+
sh 'git commit -m "Update CHANGELOG.md in preparation for release"'
72+
end
73+
74+
stage('TagProject', 'Tag the project') do
75+
sh "git tag v#{ENV['PRODUCT_VERSION']}"
76+
end
77+
78+
stage('PatchChangelogPostRelease', 'Patch the changelog post release to prepare for next development iteration') do
79+
changelog = IO.read('CHANGELOG.md')
80+
changelog = changelog.gsub("# Change Log\n", <<HEADER)
81+
# Change Log
82+
83+
### Unreleased
84+
HEADER
85+
IO.write('CHANGELOG.md', changelog)
86+
87+
`bundle exec zapwhite`
88+
sh 'git add CHANGELOG.md'
89+
sh 'git commit -m "Update CHANGELOG.md in preparation for next development iteration"'
90+
end
91+
92+
stage('PushChanges', 'Push changes to git repository') do
93+
sh 'git push'
94+
sh 'git push --tags'
95+
end
96+
97+
stage('GithubRelease', 'Create a Release on GitHub') do
98+
changelog = IO.read('CHANGELOG.md')
99+
start = changelog.index("### [v#{ENV['PRODUCT_VERSION']}]")
100+
raise "Unable to locate version #{ENV['PRODUCT_VERSION']} in change log" if -1 == start
101+
start = changelog.index("\n", start)
102+
start = changelog.index("\n", start + 1)
103+
104+
end_index = changelog.index('### [v', start)
105+
106+
changes = changelog[start, end_index - start]
107+
108+
changes = changes.strip
109+
110+
tag = "v#{ENV['PRODUCT_VERSION']}"
111+
112+
require 'octokit'
113+
114+
client = Octokit::Client.new(:netrc => true, :auto_paginate => true)
115+
client.login
116+
client.create_release('react4j/react4j-widget', tag, :name => tag, :body => changes, :draft => false, :prerelease => true)
117+
118+
candidates = client.list_milestones('react4j/react4j-widget').select {|m| m[:title].to_s == tag}
119+
unless candidates.empty?
120+
milestone = candidates[0]
121+
unless milestone[:state] == 'closed'
122+
client.update_milestone('react4j/react4j-widget', milestone[:number], :state => 'closed')
123+
end
124+
end
125+
end
126+
end
127+
128+
if ENV['STAGE']
129+
raise "Invalid STAGE specified '#{ENV['STAGE']}' that did not match any stage"
130+
end
131+
end

0 commit comments

Comments
 (0)