released 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 16ad85ccdafa69e73909d4f175e292aea0b13fd3
4
- data.tar.gz: 768b7e7e8bc22e4e0d6e406e0b89df6573ea2046
3
+ metadata.gz: fab7a728ee7f9ddc1d86e930cc73b61dde1aabb8
4
+ data.tar.gz: 3499f338230eb9569a2521091237ef3fe7dd51c4
5
5
  SHA512:
6
- metadata.gz: 15ddba448b7ba2e02991a4e2721e35032074bbe648d527e48da881745e62f1f1809b2dfa1f95f2b756d2dde3c1b7c315af88fb5bd96859e97b606f17e2f8637a
7
- data.tar.gz: f4b2de9c067cc3d0a2ff08522a2c95967d50b4905a55d9efa2ec1d091085c7c121f9d070a8df765b27af71f553d12e0c8527680981f4f0922cae2be9c1210607
6
+ metadata.gz: f0db6f2591d68a924ead6cd71c30016aa2976ccf834be39101ec69cdccfe5f850c466bdd6e3ac0c1fa4a71d5e316df88ac992acdca0c47022cd2c1bbcf31ead2
7
+ data.tar.gz: 19e96e14c94e96f7a6dc3bba1ede47003c55558c7ac9de213f9655725e58b435836eebb51e97724192e774417807a3fdde7dae7e7775cc270bcaf75008097b56
data/Gemfile CHANGED
@@ -7,9 +7,9 @@ group :devel do
7
7
  gem 'geminabox'
8
8
  gem 'json', '~> 2.0'
9
9
  gem 'rake'
10
+ gem 'rspec'
10
11
  gem 'rspec-its'
11
12
  gem 'rspec-mocks'
12
- gem 'rspec'
13
13
  gem 'rubocop'
14
14
  gem 'vcr'
15
15
  gem 'webmock'
@@ -1,14 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- released (0.0.1)
4
+ released (0.0.2)
5
5
  ddplugin (~> 1.0)
6
- gems
7
- git
8
- nanoc (~> 4.4)
9
- netrc
10
- octokit
11
- twitter
6
+ gems (~> 0.8)
7
+ git (~> 1.3)
8
+ netrc (~> 0.11)
9
+ octokit (~> 4.6)
10
+ twitter (~> 4.8)
12
11
 
13
12
  GEM
14
13
  remote: https://rubygems.org/
@@ -17,15 +16,11 @@ GEM
17
16
  public_suffix (~> 2.0, >= 2.0.2)
18
17
  ast (2.3.0)
19
18
  builder (3.2.2)
20
- colored (1.2)
21
- concurrent-ruby (1.0.2)
22
19
  crack (0.4.3)
23
20
  safe_yaml (~> 1.0.0)
24
- cri (2.7.0)
25
- colored (~> 1.2)
26
21
  ddplugin (1.0.0)
27
22
  diff-lcs (1.2.5)
28
- faraday (0.10.0)
23
+ faraday (0.9.2)
29
24
  multipart-post (>= 1.2, < 3)
30
25
  fuubar (2.2.0)
31
26
  rspec-core (~> 3.0)
@@ -38,24 +33,16 @@ GEM
38
33
  sinatra (>= 1.2.7)
39
34
  gems (0.8.3)
40
35
  git (1.3.0)
41
- hamster (3.0.0)
42
- concurrent-ruby (~> 1.0)
43
36
  hashdiff (0.3.1)
44
37
  httpclient (2.8.2.4)
45
38
  json (2.0.2)
46
39
  multi_json (1.12.1)
47
40
  multipart-post (2.0.0)
48
- nanoc (4.4.2)
49
- cri (~> 2.3)
50
- hamster (~> 3.0)
51
- parallel (~> 1.9)
52
- ref (~> 2.0)
53
41
  nesty (1.0.2)
54
42
  netrc (0.11.0)
55
43
  octokit (4.6.2)
56
44
  sawyer (~> 0.8.0, >= 0.5.3)
57
- parallel (1.10.0)
58
- parser (2.3.2.0)
45
+ parser (2.3.3.1)
59
46
  ast (~> 2.2)
60
47
  powerpack (0.1.1)
61
48
  public_suffix (2.0.4)
@@ -64,7 +51,6 @@ GEM
64
51
  rack
65
52
  rainbow (2.1.0)
66
53
  rake (11.3.0)
67
- ref (2.0.0)
68
54
  rspec (3.5.0)
69
55
  rspec-core (~> 3.5.0)
70
56
  rspec-expectations (~> 3.5.0)
@@ -81,7 +67,7 @@ GEM
81
67
  diff-lcs (>= 1.2.0, < 2.0)
82
68
  rspec-support (~> 3.5.0)
83
69
  rspec-support (3.5.0)
84
- rubocop (0.45.0)
70
+ rubocop (0.46.0)
85
71
  parser (>= 2.3.1.1, < 3.0)
86
72
  powerpack (~> 0.1)
87
73
  rainbow (>= 1.99.1, < 3.0)
@@ -98,9 +84,9 @@ GEM
98
84
  rack-protection (~> 1.4)
99
85
  tilt (>= 1.3, < 3)
100
86
  tilt (2.0.5)
101
- twitter (4.4.2)
102
- faraday (~> 0.8)
103
- multi_json (~> 1.3)
87
+ twitter (4.8.1)
88
+ faraday (~> 0.8, < 0.10)
89
+ multi_json (~> 1.0)
104
90
  simple_oauth (~> 0.2)
105
91
  unicode-display_width (1.1.1)
106
92
  vcr (3.0.3)
data/README.md CHANGED
@@ -113,8 +113,17 @@ Strings in `pipeline.yaml` will be replaced according the following rules:
113
113
 
114
114
  * Strings starting with `sh!` will be replaced with the output of the shell command following the exclamation mark. For example, `version: sh!echo -n 0.1.2` will become `version: 0.1.2`.
115
115
 
116
+ * Strings starting with `var!` will be replaced with the value of the named variable. See below for details on how to set variables. For example, `version: var!version` will become `version: 0.1.2`, if the `version` variable is set to `0.1.2`.
117
+
116
118
  * Strings starting with `-----BEGIN PGP MESSAGE-----` will be replaced with their content passed through `gpg --decrypt`.
117
119
 
120
+ The pipeline file can contain a `vars` section, which defines variables. The keys are variable names, and the value are the variable values. For example, the following defines a variable `version` with the contents of `Released::VERSION`, defined in `lib/released/version.rb`:
121
+
122
+ ```yaml
123
+ vars:
124
+ version: sh!ruby -r./lib/released/version -e 'print Released::VERSION'
125
+ ```
126
+
118
127
  ## Defining custom goal types
119
128
 
120
129
  To define a custom goal type, subclass `Released::Goal` and give it an identifier:
data/Rakefile CHANGED
@@ -3,7 +3,7 @@ require 'rspec/core/rake_task'
3
3
 
4
4
  RuboCop::RakeTask.new(:rubocop) do |task|
5
5
  task.options = %w(--display-cop-names --format simple)
6
- task.patterns = ['bin/*', 'lib/**/*.rb', 'spec/**/*.rb']
6
+ task.patterns = ['bin/*', 'lib/**/*.rb', 'spec/**/*.rb', 'Gemfile', 'Rakefile', '*.gemspec']
7
7
  end
8
8
 
9
9
  RSpec::Core::RakeTask.new(:spec) do |t|
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'released'
4
+ require 'yaml'
5
+
6
+ opts, args = ARGV.partition { |a| a.start_with?('-') }
7
+
8
+ if args.size != 1
9
+ $stderr.puts "usage: #{$PROGRAM_NAME} [options] filename"
10
+ exit 1
11
+ end
12
+
13
+ dry_run = opts.include?('--dry-run')
14
+
15
+ goals = Released::PipelineReader.new(args[0]).read
16
+ Released::Runner.new(goals, dry_run: dry_run).run
@@ -8,10 +8,10 @@ require 'shellwords'
8
8
  require 'uri'
9
9
 
10
10
  require 'ddplugin'
11
- require 'nanoc'
12
11
 
13
12
  require_relative 'released/version'
14
13
  require_relative 'released/goal'
15
14
  require_relative 'released/runner'
15
+ require_relative 'released/piper'
16
16
  require_relative 'released/pipeline_reader'
17
17
  require_relative 'released/goals'
@@ -7,5 +7,6 @@ require_relative 'goals/file_exists'
7
7
  require_relative 'goals/gem_built'
8
8
  require_relative 'goals/gem_pushed'
9
9
  require_relative 'goals/git_ref_pushed'
10
+ require_relative 'goals/git_tag_exists'
10
11
  require_relative 'goals/github_release_exists'
11
12
  require_relative 'goals/shell'
@@ -8,6 +8,10 @@ module Released
8
8
  @contents = config.fetch('contents')
9
9
  end
10
10
 
11
+ def to_s
12
+ "file exists (#{@filename})"
13
+ end
14
+
11
15
  def try_achieve
12
16
  File.write(@filename, @contents)
13
17
  end
@@ -13,12 +13,9 @@ module Released
13
13
  end
14
14
 
15
15
  def try_achieve
16
- # TODO: remove
17
- Dir['*.gem'].each { |f| FileUtils.rm_f(f) }
18
-
19
16
  stdout = ''
20
17
  stderr = ''
21
- piper = Nanoc::Extra::Piper.new(stdout: stdout, stderr: stderr)
18
+ piper = Released::Piper.new(stdout: stdout, stderr: stderr)
22
19
 
23
20
  begin
24
21
  gemspec_file_path = "#{@name}.gemspec"
@@ -33,7 +30,7 @@ module Released
33
30
  end
34
31
 
35
32
  def failure_reason
36
- "expected the file #{expected_name} to exist"
33
+ "file #{expected_name} does not exist"
37
34
  end
38
35
 
39
36
  private
@@ -53,7 +53,7 @@ module Released
53
53
  end
54
54
 
55
55
  def failure_reason
56
- "expected list of gems to contain “#{@name}”, version #{@version}"
56
+ "list of gems does not contain “#{@name}”, version #{@version}"
57
57
  end
58
58
  end
59
59
  end
@@ -8,25 +8,27 @@ module Released
8
8
  def initialize(config)
9
9
  @working_dir = config.fetch('working_dir')
10
10
  @remote = config.fetch('remote')
11
- @branch = config.fetch('branch')
11
+ @ref = config.fetch('ref')
12
+ end
13
+
14
+ def to_s
15
+ "Git ref pushed (#{@remote}/#{@ref})"
12
16
  end
13
17
 
14
18
  def try_achieve
15
- g.push(@remote, @branch)
19
+ g.push(@remote, @ref)
16
20
  end
17
21
 
18
22
  def achieved?
19
- there_branch = g.branches["#{@remote}/#{@branch}"]
20
- return false if there_branch.nil?
21
- there = there_branch.gcommit.sha
22
-
23
- here = g.object('HEAD').sha
24
-
25
- here == there
23
+ local_sha == remote_sha
26
24
  end
27
25
 
28
26
  def failure_reason
29
- "HEAD does not exist on #{@remote}/#{@branch}"
27
+ if remote_sha
28
+ "ref #{@ref} (#{abbr local_sha}) is not the same as #{@remote}/#{@ref} (#{abbr remote_sha})"
29
+ else
30
+ "ref #{@ref} (#{abbr local_sha}) does not exist on remote #{@remote}"
31
+ end
30
32
  end
31
33
 
32
34
  private
@@ -34,6 +36,21 @@ module Released
34
36
  def g
35
37
  @_g ||= Git.open(@working_dir)
36
38
  end
39
+
40
+ def abbr(sha)
41
+ sha && sha[0..7]
42
+ end
43
+
44
+ def remote_sha
45
+ remote_url = g.remote(@remote).url
46
+ res = Git.ls_remote(remote_url)
47
+ ref = res['branches'].merge(res['tags']).find { |name, _data| name == @ref }
48
+ ref ? ref[1][:sha] : nil
49
+ end
50
+
51
+ def local_sha
52
+ g.object(@ref).sha
53
+ end
37
54
  end
38
55
  end
39
56
  end
@@ -0,0 +1,48 @@
1
+ require 'git'
2
+
3
+ module Released
4
+ module Goals
5
+ class GitTagExists < Released::Goal
6
+ identifier :git_tag_exists
7
+
8
+ def initialize(config)
9
+ @working_dir = config.fetch('working_dir')
10
+ @name = config.fetch('name')
11
+ @ref = config.fetch('ref')
12
+ end
13
+
14
+ # git tag --sign --annotate 2.7.1 --message 'Version 2.7.1'
15
+
16
+ def to_s
17
+ "Git tag exists (#{@name}, ref #{@ref})"
18
+ end
19
+
20
+ def try_achieve
21
+ g.add_tag(@name, @ref)
22
+ end
23
+
24
+ def achieved?
25
+ g.tags.any? { |t| t.name == @name && t.sha == ref_sha }
26
+ end
27
+
28
+ def failure_reason
29
+ tag_with_name = g.tags.find { |t| t.name == @name }
30
+ if tag_with_name
31
+ "tag named #{@name} points to different rev"
32
+ else
33
+ "no tag named #{@name} exists"
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def g
40
+ @_g ||= Git.open(@working_dir)
41
+ end
42
+
43
+ def ref_sha
44
+ g.object(@ref).sha
45
+ end
46
+ end
47
+ end
48
+ end
@@ -11,6 +11,10 @@ module Released
11
11
  @release_notes = config.fetch('release_notes')
12
12
  end
13
13
 
14
+ def to_s
15
+ "GitHub release exists (#{@tag} in #{@repository_name})"
16
+ end
17
+
14
18
  def try_achieve
15
19
  client = Octokit::Client.new(netrc: true)
16
20
  client.create_release(
@@ -23,7 +23,7 @@ module Released
23
23
  def try_achieve
24
24
  stdout = ''
25
25
  stderr = ''
26
- piper = Nanoc::Extra::Piper.new(stdout: stdout, stderr: stderr)
26
+ piper = Released::Piper.new(stdout: stdout, stderr: stderr)
27
27
 
28
28
  begin
29
29
  piper.run(@command, [])
@@ -35,6 +35,10 @@ module Released
35
35
  def achieved?
36
36
  false
37
37
  end
38
+
39
+ def failure_reason
40
+ 'command not executed'
41
+ end
38
42
  end
39
43
  end
40
44
  end
@@ -5,7 +5,7 @@ module Released
5
5
  end
6
6
 
7
7
  def read
8
- yaml = transform(YAML.load_file(@filename))
8
+ yaml = transform_root(YAML.load_file(@filename))
9
9
 
10
10
  goals = []
11
11
 
@@ -22,37 +22,44 @@ module Released
22
22
 
23
23
  private
24
24
 
25
- def transform(obj)
25
+ def transform_root(obj)
26
+ vars = transform(obj['vars'], {})
27
+ { 'goals' => transform(obj['goals'], vars) }
28
+ end
29
+
30
+ def transform(obj, vars)
26
31
  case obj
27
32
  when Hash
28
- transform_hash(obj)
33
+ transform_hash(obj, vars)
29
34
  when Array
30
- transform_array(obj)
35
+ transform_array(obj, vars)
31
36
  when String
32
- transform_string(obj)
37
+ transform_string(obj, vars)
33
38
  else
34
39
  obj
35
40
  end
36
41
  end
37
42
 
38
- def transform_hash(hash)
43
+ def transform_hash(hash, vars)
39
44
  hash.each_with_object({}) do |(key, value), memo|
40
- memo[key] = transform(value)
45
+ memo[key] = transform(value, vars)
41
46
  end
42
47
  end
43
48
 
44
- def transform_array(array)
49
+ def transform_array(array, vars)
45
50
  array.map do |elem|
46
- transform(elem)
51
+ transform(elem, vars)
47
52
  end
48
53
  end
49
54
 
50
- def transform_string(string)
55
+ def transform_string(string, vars)
51
56
  case string
52
57
  when /\Aenv!(.*)/
53
58
  ENV.fetch(Regexp.last_match(1))
54
59
  when /\Ash!(.*)/
55
60
  `#{Regexp.last_match(1)}`
61
+ when /\Avar!(.*)/
62
+ vars[Regexp.last_match(1)]
56
63
  when /\A-----BEGIN PGP MESSAGE-----/
57
64
  decrypt(string)
58
65
  else
@@ -64,7 +71,7 @@ module Released
64
71
  stdout = ''
65
72
  stderr = ''
66
73
 
67
- piper = Nanoc::Extra::Piper.new(stdout: stdout, stderr: stderr)
74
+ piper = Released::Piper.new(stdout: stdout, stderr: stderr)
68
75
  piper.run(['gpg', '--decrypt', '--no-tty'], string)
69
76
 
70
77
  stdout
@@ -0,0 +1,46 @@
1
+ require 'open3'
2
+
3
+ module Released
4
+ class Piper
5
+ class Error < StandardError
6
+ def initialize(command, exit_code)
7
+ @command = command
8
+ @exit_code = exit_code
9
+ end
10
+
11
+ def message
12
+ "command exited with a nonzero status code #{@exit_code} (command: #{@command.join(' ')})"
13
+ end
14
+ end
15
+
16
+ # @param [IO] stdout
17
+ # @param [IO] stderr
18
+ def initialize(stdout: $stdout, stderr: $stderr)
19
+ @stdout = stdout
20
+ @stderr = stderr
21
+ end
22
+
23
+ # @param [Array<String>] cmd
24
+ #
25
+ # @param [String, nil] input
26
+ def run(cmd, input)
27
+ Open3.popen3(*cmd) do |stdin, stdout, stderr, wait_thr|
28
+ stdout_thread = Thread.new { @stdout << stdout.read }
29
+ stderr_thread = Thread.new { @stderr << stderr.read }
30
+
31
+ if input
32
+ stdin << input
33
+ end
34
+ stdin.close
35
+
36
+ stdout_thread.join
37
+ stderr_thread.join
38
+
39
+ exit_status = wait_thr.value
40
+ unless exit_status.success?
41
+ raise Error.new(cmd, exit_status.to_i)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -55,10 +55,15 @@ module Released
55
55
  private
56
56
 
57
57
  def print_goals
58
+ # Create space
59
+ @goals.each { puts }
60
+ @tui.move_up(@goals.size)
61
+
58
62
  @goals.each do |goal|
59
63
  left.times { $stdout << '. ' }
60
64
 
61
65
  @tui.move_to_left
66
+ $stdout << ' '
62
67
  $stdout << goal
63
68
  $stdout << ' '
64
69
 
@@ -92,7 +97,7 @@ module Released
92
97
  end
93
98
 
94
99
  def left
95
- @_left ||= @goals.map { |g| g.to_s.size }.max + 5
100
+ @_left ||= @goals.map { |g| g.to_s.size }.max + 8
96
101
  end
97
102
 
98
103
  def assess_all
@@ -136,7 +141,7 @@ module Released
136
141
  if goal.achieved?
137
142
  write_state(idx, left, 'ok (already achieved)')
138
143
  else
139
- write_state(idx, left, 'pending')
144
+ write_state(idx, left, 'pending: ' + goal.failure_reason)
140
145
  end
141
146
  next
142
147
  end
@@ -162,7 +167,9 @@ module Released
162
167
  write_state(idx, left, 'ok (newly achieved)')
163
168
  next
164
169
  else
165
- write_state(idx, left, 'failed')
170
+ write_state(idx, left, 'failed: ' + goal.failure_reason)
171
+ puts
172
+ puts 'Failed!'
166
173
  exit 1 # FIXME: eww
167
174
  end
168
175
  end
@@ -1,3 +1,3 @@
1
1
  module Released
2
- VERSION = '0.0.1'.freeze
2
+ VERSION = '0.0.2'.freeze
3
3
  end
@@ -13,24 +13,22 @@ Gem::Specification.new do |s|
13
13
 
14
14
  s.files =
15
15
  Dir['[A-Z]*'] +
16
- Dir['{lib,spec}/**/*'] +
16
+ Dir['{bin,lib,spec}/**/*'] +
17
17
  Dir['*.gemspec']
18
- s.require_paths = ['lib']
18
+ s.executables = ['released']
19
+ s.require_paths = ['lib']
19
20
 
20
- s.rdoc_options = ['--main', 'README.md']
21
+ s.rdoc_options = ['--main', 'README.md']
21
22
 
22
23
  s.required_ruby_version = '>= 2.3.0'
23
24
 
24
25
  # Dependencies for goals
25
26
  # TODO: Move into plugins
26
- s.add_runtime_dependency('git')
27
- s.add_runtime_dependency('twitter')
28
- s.add_runtime_dependency('gems')
29
- s.add_runtime_dependency('netrc')
30
- s.add_runtime_dependency('octokit')
31
-
32
- # TODO: Remove this (copy piper?)
33
- s.add_runtime_dependency('nanoc', '~> 4.4')
27
+ s.add_runtime_dependency('git', '~> 1.3')
28
+ s.add_runtime_dependency('twitter', '~> 4.8')
29
+ s.add_runtime_dependency('gems', '~> 0.8')
30
+ s.add_runtime_dependency('netrc', '~> 0.11')
31
+ s.add_runtime_dependency('octokit', '~> 4.6')
34
32
 
35
33
  s.add_runtime_dependency('ddplugin', '~> 1.0')
36
34
 
@@ -54,11 +54,23 @@ describe Released::Goals::GemBuilt do
54
54
  it 'builds the gem' do
55
55
  expect { subject }.to change { File.file?('donkey-0.1.gem') }.from(false).to(true)
56
56
  end
57
+
58
+ context 'other gems already exist' do
59
+ before { File.write('foo-1.0.gem', 'stuff') }
60
+
61
+ it 'builds the gem' do
62
+ expect { subject }.to change { File.file?('donkey-0.1.gem') }.from(false).to(true)
63
+ end
64
+
65
+ it 'does not remove other gems' do
66
+ expect { subject }.not_to change { File.file?('foo-1.0.gem') }
67
+ end
68
+ end
57
69
  end
58
70
  end
59
71
 
60
72
  describe '#failure_reason' do
61
73
  subject { goal.failure_reason }
62
- it { is_expected.to eql('expected the file donkey-0.1.gem to exist') }
74
+ it { is_expected.to eql('file donkey-0.1.gem does not exist') }
63
75
  end
64
76
  end
@@ -144,6 +144,10 @@ describe Released::Goals::GemPushed, stdio: true do
144
144
  end
145
145
 
146
146
  describe '#failure_reason' do
147
- # TODO
147
+ subject { goal.failure_reason }
148
+
149
+ let(:authorization) { incorrect_authorization } # irrelevant
150
+
151
+ it { is_expected.to eql('list of gems does not contain “nanoc”, version 4.4.2') }
148
152
  end
149
153
  end
@@ -7,10 +7,12 @@ describe Released::Goals::GitRefPushed do
7
7
  {
8
8
  'working_dir' => 'local',
9
9
  'remote' => 'gitlab',
10
- 'branch' => 'devel',
10
+ 'ref' => config_ref,
11
11
  }
12
12
  end
13
13
 
14
+ let(:config_ref) { 'devel' }
15
+
14
16
  let!(:local) do
15
17
  Git.init('local').tap do |g|
16
18
  g.config('user.name', 'Testy McTestface')
@@ -20,6 +22,7 @@ describe Released::Goals::GitRefPushed do
20
22
  g.add('hello.txt')
21
23
  g.commit('Add greeting')
22
24
  g.branch('devel').checkout
25
+ g.add_tag('1.2.4')
23
26
  end
24
27
  end
25
28
 
@@ -34,41 +37,100 @@ describe Released::Goals::GitRefPushed do
34
37
  describe '#achieved?' do
35
38
  subject { goal.achieved? }
36
39
 
37
- context 'not pushed' do
38
- it { is_expected.not_to be }
39
- end
40
+ context 'pushing branch' do
41
+ context 'not pushed' do
42
+ it { is_expected.not_to be }
43
+ end
40
44
 
41
- context 'pushed, but not right rev' do
42
- before do
43
- goal.try_achieve
45
+ context 'pushed, but not right rev' do
46
+ before do
47
+ goal.try_achieve
44
48
 
45
- local.chdir { File.write('bye.txt', 'bye now') }
46
- local.add('bye.txt')
47
- local.commit('Add farewell')
48
- local.branch('devel').checkout
49
+ local.chdir { File.write('bye.txt', 'bye now') }
50
+ local.add('bye.txt')
51
+ local.commit('Add farewell')
52
+ local.branch('devel').checkout
53
+ end
54
+
55
+ it { is_expected.not_to be }
49
56
  end
50
57
 
51
- it { is_expected.not_to be }
58
+ context 'pushed' do
59
+ before { goal.try_achieve }
60
+ it { is_expected.to be }
61
+ end
52
62
  end
53
63
 
54
- context 'pushed' do
55
- before { goal.try_achieve }
56
- it { is_expected.to be }
64
+ context 'pushing tag' do
65
+ let(:config_ref) { '1.2.4' }
66
+
67
+ context 'not pushed' do
68
+ it { is_expected.not_to be }
69
+ end
70
+
71
+ context 'pushed, but not right rev' do
72
+ before do
73
+ goal.try_achieve
74
+
75
+ local.chdir { File.write('bye.txt', 'bye now') }
76
+ local.add('bye.txt')
77
+ local.commit('Add farewell')
78
+ local.delete_tag('1.2.4')
79
+ local.add_tag('1.2.4')
80
+ end
81
+
82
+ it { is_expected.not_to be }
83
+ end
84
+
85
+ context 'pushed' do
86
+ before { goal.try_achieve }
87
+ it { is_expected.to be }
88
+ end
57
89
  end
58
90
  end
59
91
 
60
92
  describe '#try_achieve' do
61
93
  subject { goal.try_achieve }
62
94
 
63
- example do
64
- expect(remote.branches['devel']).to be_nil
65
- subject
66
- expect(remote.branches['devel'].gcommit.sha).to eql(local.branches['devel'].gcommit.sha)
95
+ context 'pushing branch' do
96
+ let(:config_ref) { 'devel' }
97
+
98
+ example do
99
+ expect(remote.branches['devel']).to be_nil
100
+ subject
101
+ expect(remote.branches['devel'].gcommit.sha).to eql(local.branches['devel'].gcommit.sha)
102
+ end
103
+ end
104
+
105
+ context 'pushing tag' do
106
+ let(:config_ref) { '1.2.4' }
107
+
108
+ example do
109
+ expect(remote.tags).to be_empty
110
+ subject
111
+ expect(remote.tag('1.2.4').sha).to eql(local.tag('1.2.4').sha)
112
+ end
67
113
  end
68
114
  end
69
115
 
70
116
  describe '#failure_reason' do
71
117
  subject { goal.failure_reason }
72
- it { is_expected.to eql('HEAD does not exist on gitlab/devel') }
118
+
119
+ context 'pushed, but not right rev' do
120
+ before do
121
+ goal.try_achieve
122
+
123
+ local.chdir { File.write('bye.txt', 'bye now') }
124
+ local.add('bye.txt')
125
+ local.commit('Add farewell')
126
+ local.branch('devel').checkout
127
+ end
128
+
129
+ it { is_expected.to match(%r{ref devel \(.{8}\) is not the same as gitlab/devel \(.{8}\)}) }
130
+ end
131
+
132
+ context 'not pushed' do
133
+ it { is_expected.to match(/ref devel \(.{8}\) does not exist on remote gitlab/) }
134
+ end
73
135
  end
74
136
  end
@@ -0,0 +1,122 @@
1
+ describe Released::Goals::GitTagExists do
2
+ subject(:goal) do
3
+ described_class.new(config)
4
+ end
5
+
6
+ let(:config) do
7
+ {
8
+ 'working_dir' => 'local',
9
+ 'name' => '1.3',
10
+ 'ref' => config_ref,
11
+ }
12
+ end
13
+
14
+ let(:config_ref) { 'HEAD' }
15
+
16
+ let!(:local) do
17
+ Git.init('local').tap do |g|
18
+ g.config('user.name', 'Testy McTestface')
19
+ g.config('user.email', 'testface@example.com')
20
+
21
+ g.chdir { File.write('hello.txt', 'hi there') }
22
+ g.add('hello.txt')
23
+ g.commit('Add greeting')
24
+ g.branch('devel').checkout
25
+ g.add_tag('sweet')
26
+ end
27
+ end
28
+
29
+ describe '#achieved?' do
30
+ subject { goal.achieved? }
31
+
32
+ context 'not tagged' do
33
+ it { is_expected.not_to be }
34
+ end
35
+
36
+ context 'tagged, but wrong rev' do
37
+ before do
38
+ local.add_tag('1.3')
39
+
40
+ local.chdir { File.write('bye.txt', 'bye now') }
41
+ local.add('bye.txt')
42
+ local.commit('Add farewell')
43
+ end
44
+
45
+ it { is_expected.not_to be }
46
+ end
47
+
48
+ context 'tagged' do
49
+ before do
50
+ local.add_tag('1.3')
51
+ end
52
+
53
+ it { is_expected.to be }
54
+ end
55
+ end
56
+
57
+ describe '#try_achieve' do
58
+ subject { goal.try_achieve }
59
+
60
+ let(:created_tag) { local.tags.find { |t| t.name == '1.3' } }
61
+
62
+ context 'referencing HEAD' do
63
+ let(:config_ref) { 'HEAD' }
64
+
65
+ example do
66
+ expect(created_tag).to be_nil
67
+ subject
68
+ expect(local.tag('1.3').sha).to eql(local.object('HEAD').sha)
69
+ end
70
+ end
71
+
72
+ context 'referencing branch' do
73
+ let(:config_ref) { 'devel' }
74
+
75
+ example do
76
+ expect(created_tag).to be_nil
77
+ subject
78
+ expect(local.tag('1.3').sha).to eql(local.object('HEAD').sha)
79
+ end
80
+ end
81
+
82
+ context 'referencing sha' do
83
+ let(:config_ref) { local.object('devel').sha }
84
+
85
+ example do
86
+ expect(created_tag).to be_nil
87
+ subject
88
+ expect(local.tag('1.3').sha).to eql(local.object('HEAD').sha)
89
+ end
90
+ end
91
+
92
+ context 'referencing tag' do
93
+ let(:config_ref) { local.object('sweet').sha }
94
+
95
+ example do
96
+ expect(created_tag).to be_nil
97
+ subject
98
+ expect(local.tag('1.3').sha).to eql(local.object('HEAD').sha)
99
+ end
100
+ end
101
+ end
102
+
103
+ describe '#failure_reason' do
104
+ subject { goal.failure_reason }
105
+
106
+ context 'not tagged' do
107
+ it { is_expected.to eql('no tag named 1.3 exists') }
108
+ end
109
+
110
+ context 'tagged, but wrong rev' do
111
+ before do
112
+ local.add_tag('1.3')
113
+
114
+ local.chdir { File.write('bye.txt', 'bye now') }
115
+ local.add('bye.txt')
116
+ local.commit('Add farewell')
117
+ end
118
+
119
+ it { is_expected.to eql('tag named 1.3 points to different rev') }
120
+ end
121
+ end
122
+ end
@@ -8,7 +8,9 @@ describe Released::PipelineReader do
8
8
  end
9
9
 
10
10
  describe '#transform' do
11
- subject { pipeline_reader.send(:transform, obj) }
11
+ subject { pipeline_reader.send(:transform, obj, vars) }
12
+
13
+ let(:vars) { {} }
12
14
 
13
15
  context 'with array' do
14
16
  let(:obj) { %w(hello env!FAVORITE_GEM_AUTHOR) }
@@ -36,6 +38,19 @@ describe Released::PipelineReader do
36
38
  it { is_expected.to eql('hello') }
37
39
  end
38
40
 
41
+ context 'var! string' do
42
+ let(:obj) { 'var!version' }
43
+
44
+ context 'var does not exist' do
45
+ # TODO
46
+ end
47
+
48
+ context 'var exists' do
49
+ let(:vars) { { 'version' => '1.2.4' } }
50
+ it { is_expected.to eql('1.2.4') }
51
+ end
52
+ end
53
+
39
54
  context 'encrypted string' do
40
55
  # TODO
41
56
  end
metadata CHANGED
@@ -1,99 +1,85 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: released
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Defreyne
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-01 00:00:00.000000000 Z
11
+ date: 2016-12-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: git
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '1.3'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '1.3'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: twitter
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '4.8'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '4.8'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: gems
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: '0.8'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: '0.8'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: netrc
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: '0.11'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: '0.11'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: octokit
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: nanoc
85
71
  requirement: !ruby/object:Gem::Requirement
86
72
  requirements:
87
73
  - - "~>"
88
74
  - !ruby/object:Gem::Version
89
- version: '4.4'
75
+ version: '4.6'
90
76
  type: :runtime
91
77
  prerelease: false
92
78
  version_requirements: !ruby/object:Gem::Requirement
93
79
  requirements:
94
80
  - - "~>"
95
81
  - !ruby/object:Gem::Version
96
- version: '4.4'
82
+ version: '4.6'
97
83
  - !ruby/object:Gem::Dependency
98
84
  name: ddplugin
99
85
  requirement: !ruby/object:Gem::Requirement
@@ -130,7 +116,8 @@ dependencies:
130
116
  version: '2.0'
131
117
  description: ''
132
118
  email: denis.defreyne@stoneship.org
133
- executables: []
119
+ executables:
120
+ - released
134
121
  extensions: []
135
122
  extra_rdoc_files: []
136
123
  files:
@@ -138,6 +125,7 @@ files:
138
125
  - Gemfile.lock
139
126
  - README.md
140
127
  - Rakefile
128
+ - bin/released
141
129
  - lib/released.rb
142
130
  - lib/released/goal.rb
143
131
  - lib/released/goals.rb
@@ -145,15 +133,18 @@ files:
145
133
  - lib/released/goals/gem_built.rb
146
134
  - lib/released/goals/gem_pushed.rb
147
135
  - lib/released/goals/git_ref_pushed.rb
136
+ - lib/released/goals/git_tag_exists.rb
148
137
  - lib/released/goals/github_release_exists.rb
149
138
  - lib/released/goals/shell.rb
150
139
  - lib/released/pipeline_reader.rb
140
+ - lib/released/piper.rb
151
141
  - lib/released/runner.rb
152
142
  - lib/released/version.rb
153
143
  - released.gemspec
154
144
  - spec/released/goals/gem_built_spec.rb
155
145
  - spec/released/goals/gem_pushed_spec.rb
156
146
  - spec/released/goals/git_ref_pushed_spec.rb
147
+ - spec/released/goals/git_tag_exists_spec.rb
157
148
  - spec/released/pipeline_reader_spec.rb
158
149
  - spec/spec_helper.rb
159
150
  homepage: https://github.com/ddfreyne/released