jara 1.0.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +12 -0
- data/README.md +26 -0
- data/lib/jara/releaser.rb +179 -0
- data/lib/jara/version.rb +5 -0
- data/lib/jara.rb +9 -0
- metadata +77 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e617ac5c7fddb9396203f924042e6acf558ef7a0
|
4
|
+
data.tar.gz: 46aa05ca9134886f3c516f04ab0005b42d97cc89
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 40091d005522a32a2e9553dba4c05a92b7acc454201db58dbf3565b711a271abed9bd4be2b4fca92b671197621261667be8c333e02baba888c862768ebd74ca1
|
7
|
+
data.tar.gz: 28e9e8589c1b5dfae7631df23be94fab4765048a6a1e78927f7c4f6f1a2d3822bccdd44dbb6fc3507c350a22b43bba2ac78baeef2e323d86a0109a7dee0db4bb
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
Copyright (c) 2014, Burt AB
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
5
|
+
|
6
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
7
|
+
|
8
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
9
|
+
|
10
|
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
11
|
+
|
12
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Jarå
|
2
|
+
|
3
|
+
Jarå builds self-contained JARs of JRuby applications and publishes them to S3. It will check that you've pushed your code, check out a pristine copy from git, build a JAR and upload it to S3.
|
4
|
+
|
5
|
+
# Usage
|
6
|
+
|
7
|
+
```
|
8
|
+
# this will build an artifact from master and upload it to
|
9
|
+
# the "artifact-bucket" on S3
|
10
|
+
releaser = Jarå::Releaser.new('production', 'artifact-bucket')
|
11
|
+
releaser.release
|
12
|
+
```
|
13
|
+
|
14
|
+
The JAR artifact will be named from the project name, environment, date stamp and commit SHA, and will be uploaded with a path on S3 that also contains the environment and project name. The name of the directory that contains the code is assumed to be the project name.
|
15
|
+
|
16
|
+
For example, if you run it from a directory called "foo_bar" and sets the environment "production" it will build the artifact "foo_bar-production-YYYYmmddHHMMSS-XXXXXXXX.jar", where "YYYYmmddHHMMSS" is the current date and time and "XXXXXXXX" is the first 8 characters from the commit SHA. The artifact will be cached locally in a directory called "build/production" and then uploaded to S3 into the specified bucket, with the key "production/foo_bar/foo_bar-production-YYYYmmddHHMMSS-XXXXXXXX.jar".
|
17
|
+
|
18
|
+
If you change "production" to "staging" it will build an artifact from the staging branch instead (and all other paths and names will have "staging" where they had "production" in the description above).
|
19
|
+
|
20
|
+
You may have noticed that specifying "production" created an artifact from the master branch, and "staging" used the staging branch. Using anything but "production" means that the branch name is assumed to be the same as the environment.
|
21
|
+
|
22
|
+
Before the artifact is built Jarå will check that _branch_name_ and origin/*branch_name* point to the same commit. The reason for this is so that you don't release an artifact with a SHA that is not visible to others (this does not check that you've pulled before you release, but the important thing is to not release something that is not trackable).
|
23
|
+
|
24
|
+
# Copyright
|
25
|
+
|
26
|
+
© 2014 Burt AB, see LICENSE.txt (BSD 3-Clause).
|
@@ -0,0 +1,179 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'tmpdir'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'pathname'
|
6
|
+
require 'puck'
|
7
|
+
require 'digest/md5'
|
8
|
+
require 'aws-sdk-core'
|
9
|
+
require 'socket'
|
10
|
+
|
11
|
+
|
12
|
+
module Jara
|
13
|
+
ExecError = Class.new(JaraError)
|
14
|
+
|
15
|
+
class Releaser
|
16
|
+
def initialize(environment, bucket_name, options={})
|
17
|
+
@environment = environment
|
18
|
+
@bucket_name = bucket_name
|
19
|
+
@shell = options[:shell] || Shell.new
|
20
|
+
@archiver = options[:archiver] || Archiver.new
|
21
|
+
@file_system = options[:file_system] || FileUtils
|
22
|
+
@s3 = options[:s3]
|
23
|
+
@logger = options[:logger] || IoLogger.new($stderr)
|
24
|
+
@branch = @environment == 'production' ? 'master' : @environment
|
25
|
+
end
|
26
|
+
|
27
|
+
def build_artifact
|
28
|
+
if @environment.nil?
|
29
|
+
jar_name = "#{app_name}.jar"
|
30
|
+
Dir.chdir(project_dir) do
|
31
|
+
@archiver.create(jar_name: jar_name)
|
32
|
+
end
|
33
|
+
@logger.info('Created test artifact')
|
34
|
+
File.join(project_dir, 'build', jar_name)
|
35
|
+
elsif (artifact_path = find_local_artifact)
|
36
|
+
@logger.warn('An artifact for %s already exists: %s' % [branch_sha[0, 8], File.basename(artifact_path)])
|
37
|
+
artifact_path
|
38
|
+
else
|
39
|
+
date_stamp = Time.now.utc.strftime('%Y%m%d%H%M%S')
|
40
|
+
destination_dir = File.join(project_dir, 'build', @environment)
|
41
|
+
jar_name = [app_name, @environment, date_stamp, branch_sha[0, 8]].join('-') << '.jar'
|
42
|
+
Dir.mktmpdir do |path|
|
43
|
+
Dir.chdir(path) do
|
44
|
+
@shell.exec('git clone %s . && git checkout %s' % [project_dir, branch_sha])
|
45
|
+
@logger.info('Checked out %s from branch %s' % [branch_sha[0, 8], @branch])
|
46
|
+
@archiver.create(jar_name: jar_name)
|
47
|
+
@file_system.mkdir_p(destination_dir)
|
48
|
+
@file_system.cp("build/#{jar_name}", destination_dir)
|
49
|
+
@logger.info('Created artifact %s' % jar_name)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
File.join(destination_dir, jar_name)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def release
|
57
|
+
raise JaraError, 'No environment set' unless @environment
|
58
|
+
raise JaraError, 'No bucket name set' unless @bucket_name
|
59
|
+
if obj = find_remote_artifact
|
60
|
+
@logger.warn('An artifact for %s already exists: s3://%s/%s' % [branch_sha[0, 8], @bucket_name, obj.key])
|
61
|
+
else
|
62
|
+
local_path = find_local_artifact || build_artifact
|
63
|
+
upload_artifact(local_path)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
JAR_CONTENT_TYPE = 'application/java-archive'
|
70
|
+
|
71
|
+
def s3
|
72
|
+
@s3 ||= Aws.s3
|
73
|
+
end
|
74
|
+
|
75
|
+
def app_name
|
76
|
+
File.basename(project_dir)
|
77
|
+
end
|
78
|
+
|
79
|
+
def project_dir
|
80
|
+
unless defined? @project_dir
|
81
|
+
Pathname.new(Dir.getwd).descend do |path|
|
82
|
+
if Dir.entries(path).include?('.git')
|
83
|
+
@project_dir = path
|
84
|
+
break
|
85
|
+
end
|
86
|
+
end
|
87
|
+
unless defined? @project_dir
|
88
|
+
raise JaraError, 'Could not find project directory'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
@project_dir
|
92
|
+
end
|
93
|
+
|
94
|
+
def branch_sha
|
95
|
+
@branch_sha ||= begin
|
96
|
+
result = @shell.exec('git rev-parse %s && git rev-parse origin/%s' % [@branch, @branch])
|
97
|
+
local_sha, remote_sha = result.split("\n").take(2)
|
98
|
+
if local_sha == remote_sha
|
99
|
+
local_sha
|
100
|
+
else
|
101
|
+
raise JaraError, '%s and origin/%s are not in sync, did you forget to push?' % [@branch, @branch]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def metadata
|
107
|
+
{
|
108
|
+
'packaged_by' => "#{ENV['USER']}@#{Socket.gethostname}",
|
109
|
+
'sha' => branch_sha
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
def find_local_artifact
|
114
|
+
candidates = Dir[File.join(project_dir, 'build', @environment, '*.jar')]
|
115
|
+
candidates.select! { |path| path.include?(branch_sha[0, 8]) }
|
116
|
+
candidates.sort.last
|
117
|
+
end
|
118
|
+
|
119
|
+
def upload_artifact(local_path)
|
120
|
+
begin
|
121
|
+
remote_path = [@environment, app_name, File.basename(local_path)].join('/')
|
122
|
+
content_md5 = Digest::MD5.file(local_path).hexdigest
|
123
|
+
File.open(local_path, 'rb') do |io|
|
124
|
+
s3.put_object(
|
125
|
+
bucket: @bucket_name,
|
126
|
+
key: remote_path,
|
127
|
+
content_type: JAR_CONTENT_TYPE,
|
128
|
+
content_md5: content_md5,
|
129
|
+
metadata: metadata,
|
130
|
+
body: io,
|
131
|
+
)
|
132
|
+
end
|
133
|
+
@logger.info('Artifact uploaded to s3://%s/%s' % [@bucket_name, remote_path])
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def find_remote_artifact
|
138
|
+
listing = s3.list_objects(bucket: @bucket_name, prefix: [@environment, app_name, "#{app_name}-#{@environment}-"].join('/'))
|
139
|
+
listing.contents.find { |obj| obj.key.include?(branch_sha[0, 8]) }
|
140
|
+
end
|
141
|
+
|
142
|
+
class Shell
|
143
|
+
def exec(command)
|
144
|
+
output = %x(#{command})
|
145
|
+
unless $?.success?
|
146
|
+
raise ExecError, %(Command `#{command}` failed with output: #{output})
|
147
|
+
end
|
148
|
+
output
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
class Archiver
|
153
|
+
def create(options)
|
154
|
+
Puck::Jar.new(options).create!
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
class IoLogger
|
160
|
+
def initialize(io)
|
161
|
+
@io = io
|
162
|
+
end
|
163
|
+
|
164
|
+
def info(msg)
|
165
|
+
@io.puts(msg)
|
166
|
+
end
|
167
|
+
|
168
|
+
def warn(msg)
|
169
|
+
@io.puts(msg)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
class NullLogger
|
174
|
+
def info(*); end
|
175
|
+
def warn(*); end
|
176
|
+
end
|
177
|
+
|
178
|
+
NULL_LOGGER = NullLogger.new
|
179
|
+
end
|
data/lib/jara/version.rb
ADDED
data/lib/jara.rb
ADDED
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jara
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: java
|
6
|
+
authors:
|
7
|
+
- Burt Platform Team
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - '>='
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '0'
|
19
|
+
name: puck
|
20
|
+
prerelease: false
|
21
|
+
type: :runtime
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
name: aws-sdk-core
|
34
|
+
prerelease: false
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Build self-contained JAR artifacts and publish them to S3
|
42
|
+
email:
|
43
|
+
- theo@burtcorp.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- LICENSE.txt
|
49
|
+
- README.md
|
50
|
+
- lib/jara.rb
|
51
|
+
- lib/jara/releaser.rb
|
52
|
+
- lib/jara/version.rb
|
53
|
+
homepage: http://github.com/burtcorp/jara
|
54
|
+
licenses:
|
55
|
+
- BSD-3-Clause
|
56
|
+
metadata: {}
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 1.9.3
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
requirements: []
|
72
|
+
rubyforge_project:
|
73
|
+
rubygems_version: 2.2.2
|
74
|
+
signing_key:
|
75
|
+
specification_version: 4
|
76
|
+
summary: Builds and publishes JAR artifacts
|
77
|
+
test_files: []
|