codefumes 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,21 +7,21 @@ Feature: Deleting a project
7
7
  Scenario: The specified project does not exist on CodeFumes.com
8
8
  When I run "#{@bin_path}/fumes delete -p bad-public-key"
9
9
  Then the output should contain "Not Found"
10
- And the exit status should be 0
10
+ And the exit status should be "SUCCESS"
11
11
 
12
12
  Scenario: Attempting to delete a project without having an API key entry in the CodeFumes config file
13
13
  Given I have cloned and synchronized 1 project
14
14
  And I have claimed the project
15
15
  When I delete the project
16
16
  Then the output should contain 1 successful delete messages
17
- And the exit status should be 0
17
+ And the exit status should be "SUCCESS"
18
18
 
19
19
  Scenario: Deleting one of multiple projects in your CodeFumes config file
20
20
  Given I have cloned and synchronized 2 projects
21
21
  And I have claimed the 1st project
22
22
  When I delete the 1st project
23
23
  Then the output should contain 1 successful delete messages
24
- And the exit status should be 0
24
+ And the exit status should be "SUCCESS"
25
25
 
26
26
  Scenario: Releasing all projects in your CodeFumes config file
27
27
  Given valid user credentials have been stored in the CodeFumes config file
@@ -29,4 +29,4 @@ Feature: Deleting a project
29
29
  And I run "#{@bin_path}/fumes claim -a"
30
30
  When I run "#{@bin_path}/fumes delete -a"
31
31
  Then the output should contain 2 successful delete messages
32
- And the exit status should be 0
32
+ And the exit status should be "SUCCESS"
@@ -0,0 +1,63 @@
1
+ Feature: Managing a project's build status
2
+ Tracking the build status of a project is one of, if not
3
+ THE primary purpose of CodeFumes.com. As the owner of a project
4
+ I want to be able to easily manage and the state of an read
5
+ the state of various builds for a project.
6
+
7
+ Scenario: Starting a build for a project
8
+ Given I have cloned and synchronized 1 project
9
+ And I cd to "project_1/"
10
+ When I run "#{@bin_path}/fumes build --start ie7"
11
+ Then the output should contain "Setting 'ie7' build status to 'started'"
12
+ And the output should contain "'ie7' build successfully marked as 'started'"
13
+ And the exit status should be "SUCCESS"
14
+
15
+ Scenario: Setting a project build status to 'failure'
16
+ Given I have cloned and synchronized 1 project
17
+ And I cd to "project_1/"
18
+ And I run "#{@bin_path}/fumes build --start ie7"
19
+ When I run "#{@bin_path}/fumes build --finished=failed ie7"
20
+ Then the output should contain "Setting 'ie7' build status to 'failed'"
21
+ And the output should contain "'ie7' build successfully marked as 'failed'"
22
+ And the exit status should be "SUCCESS"
23
+
24
+ Scenario: Setting a project build status to an invalid state
25
+ Given I have cloned and synchronized 1 project
26
+ And I cd to "project_1/"
27
+ And I run "#{@bin_path}/fumes build --start ie7"
28
+ When I run "#{@bin_path}/fumes build --finished=badstate ie7"
29
+ Then the output should contain "Invalid build state"
30
+ And the exit status should be "INVALID_BUILD_STATE"
31
+
32
+ Scenario: Attempting to set multiple build states in same command
33
+ Given I have cloned and synchronized 1 project
34
+ And I cd to "project_1/"
35
+ And I run "#{@bin_path}/fumes build --start ie7"
36
+ When I run "#{@bin_path}/fumes build --finished=failed --start ie7"
37
+ Then the output should contain "multiple states"
38
+ And the exit status should be "INVALID_COMMAND_SYNTAX"
39
+
40
+ Scenario: Retrieving the current build state of a specific build
41
+ Given I have cloned and synchronized 1 project
42
+ And I cd to "project_1/"
43
+ And I run "#{@bin_path}/fumes build --start ie7"
44
+ When I run "#{@bin_path}/fumes build --status ie7"
45
+ Then the output should contain "running"
46
+ And the exit status should be "SUCCESS"
47
+
48
+ Scenario: Retrieving the current build state of a all builds of the latest commit
49
+ Given I have cloned and synchronized 1 project
50
+ And I cd to "project_1/"
51
+ And I run "#{@bin_path}/fumes build --start ie7"
52
+ And I run "#{@bin_path}/fumes build --start specs"
53
+ When I run "#{@bin_path}/fumes build --status --all"
54
+ Then the output should contain 2 running build status messages
55
+ And the exit status should be "SUCCESS"
56
+
57
+ Scenario: Running the build command without any arguments
58
+ Given I have cloned and synchronized 1 project
59
+ And I cd to "project_1/"
60
+ When I run "#{@bin_path}/fumes build"
61
+ Then the output should contain "build [options]"
62
+ Then the output should contain "Options:"
63
+ And the exit status should be "SUCCESS"
@@ -7,14 +7,14 @@ Feature: Claiming a project
7
7
  Given valid user credentials have been stored in the CodeFumes config file
8
8
  When I run "#{@bin_path}/fumes release -p bad-public-key"
9
9
  Then the output should contain "Not Found"
10
- And the exit status should be 0
10
+ And the exit status should be "SUCCESS"
11
11
 
12
12
  Scenario: Attempting to claim a project without having an API key entry in the CodeFumes config file
13
13
  And I have cloned and synchronized 1 project
14
14
  And I have claimed the project
15
15
  When I release the project
16
16
  Then the output should contain instructions about storing your API key
17
- And the exit status should be 3
17
+ And the exit status should be "NO_USER_CREDENTIALS"
18
18
 
19
19
  Scenario: Attempting to release a project with an invalid API key entry in the user's CodeFumes config file
20
20
  Given invalid user credentials have been stored in the CodeFumes config file
@@ -23,7 +23,7 @@ Feature: Claiming a project
23
23
  And invalid user credentials have been stored in the CodeFumes config file
24
24
  When I release the project
25
25
  Then the output should contain "Denied"
26
- And the exit status should be 0
26
+ And the exit status should be "SUCCESS"
27
27
 
28
28
  Scenario: Releasing a project using the key stored in a CodeFumes project directory
29
29
  Given valid user credentials have been stored in the CodeFumes config file
@@ -31,7 +31,7 @@ Feature: Claiming a project
31
31
  And I have claimed the project
32
32
  When I release the project
33
33
  Then the output should contain "Success"
34
- And the exit status should be 0
34
+ And the exit status should be "SUCCESS"
35
35
 
36
36
  Scenario: Releasing one of multiple projects in your CodeFumes config file
37
37
  Given valid user credentials have been stored in the CodeFumes config file
@@ -39,7 +39,7 @@ Feature: Claiming a project
39
39
  And I have claimed the 1st project
40
40
  When I release the 1st project
41
41
  Then the output should contain 1 successful release message
42
- And the exit status should be 0
42
+ And the exit status should be "SUCCESS"
43
43
 
44
44
  Scenario: Releasing all projects in your CodeFumes config file
45
45
  Given valid user credentials have been stored in the CodeFumes config file
@@ -47,4 +47,4 @@ Feature: Claiming a project
47
47
  And I run "#{@bin_path}/fumes claim -a"
48
48
  When I run "#{@bin_path}/fumes release -a"
49
49
  Then the output should contain 2 successful release messages
50
- And the exit status should be 0
50
+ And the exit status should be "SUCCESS"
@@ -1,8 +1,8 @@
1
1
  # still a super-hack...but at least it's not duplicated, right?
2
2
  # ...
3
3
  # ...right?
4
- def output_message_qty(action)
5
- combined_output.scan(/#{action}\.\.\.'.*': Success/).count
4
+ def output_message_qty(action, result = "Success")
5
+ combined_output.scan(/#{action}\.\.\.'.*': #{result}/).count
6
6
  end
7
7
 
8
8
  def clone_fixture_repo_into(dir_name)
@@ -24,6 +24,12 @@ Then /^the output should contain (\d+) successful delete message[s]?$/ do |count
24
24
  output_message_qty("Deleting").should == count.to_i
25
25
  end
26
26
 
27
+ # TODO: Get a better way of testing this...output is horrible
28
+ Then /^the output should contain (\d+) running build status message[s]?$/ do |count|
29
+ running_status_count = combined_output.scan(/'.*' build: running/).count
30
+ running_status_count.should == count.to_i
31
+ end
32
+
27
33
  Then /^the output should contain instructions about storing your API key$/ do
28
34
  Then "the output should contain \"fumes setup\""
29
35
  end
@@ -96,3 +102,7 @@ Then /^the API key in the config file should be ("[^"]*"|cleared)$/ do |api_key_
96
102
  expected_value = api_key_value == 'cleared' ? nil : api_key_value.gsub(/"/,'')
97
103
  ConfigFile.api_key.should == expected_value
98
104
  end
105
+
106
+ Then /^the exit status should be "([^"]*)"$/ do |exit_code_name|
107
+ Then "the exit status should be #{instance_eval("CodeFumes::ExitCodes::#{exit_code_name}")}"
108
+ end
@@ -10,7 +10,7 @@ Feature: Storing a User's API key
10
10
  """
11
11
  No API key specified
12
12
  """
13
- And the exit status should be 5
13
+ And the exit status should be "NO_API_KEY_SPECIFIED"
14
14
 
15
15
  Scenario: Issuing 'api-key' with an argument
16
16
  When I run "#{@bin_path}/fumes api-key userkey"
@@ -19,7 +19,7 @@ Feature: Storing a User's API key
19
19
  Your API key has been saved to your CodeFumes config file
20
20
  """
21
21
  And the API key in the config file should be "userkey"
22
- And the exit status should be 0
22
+ And the exit status should be "SUCCESS"
23
23
 
24
24
  Scenario: Issuing 'api-key' with the --clear flag
25
25
  When I run "#{@bin_path}/fumes api-key --clear"
@@ -28,7 +28,7 @@ Feature: Storing a User's API key
28
28
  Your API key has been removed from your CodeFumes config file
29
29
  """
30
30
  And the API key in the config file should be cleared
31
- And the exit status should be 0
31
+ And the exit status should be "SUCCESS"
32
32
 
33
33
  Scenario: Issuing 'api-key' with the --clear flag and an argument
34
34
  When I run "#{@bin_path}/fumes api-key userkey1"
@@ -38,4 +38,4 @@ Feature: Storing a User's API key
38
38
  Your API key has been removed from your CodeFumes config file
39
39
  """
40
40
  And the API key in the config file should be cleared
41
- And the exit status should be 0
41
+ And the exit status should be "SUCCESS"
@@ -10,12 +10,12 @@ Feature: Synchronizing a repository with CodeFumes
10
10
  """
11
11
  Unsupported
12
12
  """
13
- And the exit status should be 1
13
+ And the exit status should be "UNSUPPORTED_SCM"
14
14
 
15
15
  Scenario: Successful synchronization
16
16
  Given I have cloned 1 project
17
17
  When I synchronize the project
18
- Then the exit status should be 0
18
+ Then the exit status should be "SUCCESS"
19
19
  And the output should contain "Successfully saved"
20
20
  And the output should contain "Visit http://"
21
21
 
@@ -24,10 +24,10 @@ Feature: Synchronizing a repository with CodeFumes
24
24
  When I synchronize the project
25
25
  Then the output should contain "non-production"
26
26
  And the output should contain "test.codefumes.com"
27
- And the exit status should be 0
27
+ And the exit status should be "SUCCESS"
28
28
 
29
29
  Scenario: Specifying a custom, but non-existant public/private key combination
30
30
  Given I have cloned 1 project
31
31
  And I cd to "project_1/"
32
32
  When I run "#{@bin_path}/fumes sync -p non-existant-pubkey -a non-existant-privkey"
33
- And the exit status should be 2
33
+ And the exit status should be "PROJECT_NOT_FOUND"
@@ -12,5 +12,5 @@ require 'codefumes/source_control.rb'
12
12
  include CodeFumes::API
13
13
 
14
14
  module CodeFumes
15
- VERSION = '0.2.2' unless defined?(CodeFumes::VERSION)
15
+ VERSION = '0.3.0' unless defined?(CodeFumes::VERSION)
16
16
  end
@@ -6,6 +6,7 @@ module CodeFumes
6
6
  # the current status (running, failed, success) and the
7
7
  # start & end times of the Build process.
8
8
  class Build
9
+ VALID_BUILD_RESULT_STATES = [:running,:failed,:successful]
9
10
  attr_reader :created_at, :api_uri, :identifier, :commit, :project
10
11
  attr_accessor :started_at, :ended_at, :state, :name
11
12
 
@@ -25,6 +26,7 @@ module CodeFumes
25
26
  @state = state.to_s
26
27
  @started_at = options[:started_at] || options['started_at'] || Time.now
27
28
  @ended_at = options[:ended_at] || options['ended_at']
29
+ validate_build_state
28
30
  end
29
31
 
30
32
  # Overrides existing attributes with those supplied in +options+. This
@@ -59,6 +61,7 @@ module CodeFumes
59
61
  # ---
60
62
  # TODO: Make this consistent w/ other class' create/update handling
61
63
  def save
64
+ validate_build_state
62
65
  response = exists? ? update : create
63
66
 
64
67
  case response.code
@@ -134,6 +137,11 @@ module CodeFumes
134
137
  def standard_content_hash
135
138
  {:name => name,:started_at => started_at, :ended_at => ended_at, :state => state}
136
139
  end
140
+
141
+ def validate_build_state
142
+ raise(Errors::InvalidBuildState) if state.nil? || state.empty?
143
+ raise(Errors::InvalidBuildState) unless VALID_BUILD_RESULT_STATES.include?(state.to_sym)
144
+ end
137
145
  end
138
146
  end
139
147
  end
@@ -139,12 +139,34 @@ module CodeFumes
139
139
  latest_commit.nil? ? nil : latest_commit.identifier
140
140
  end
141
141
 
142
+ # Returns the all associated builds
143
+ def builds
144
+ response = API.get("/projects/#{project.public_key}/commits/#{identifier}/builds")
145
+
146
+ case response.code
147
+ when 200
148
+ builds_returned(response).map do |build_data|
149
+ build_name = build_data.delete("name")
150
+ build_state = build_data.delete("state")
151
+ Build.new(self, build_name, build_state, build_data)
152
+ end
153
+ else
154
+ nil
155
+ end
156
+ end
157
+
142
158
  private
143
159
  def convert_custom_attributes_keys_to_symbols
144
160
  @custom_attributes = @custom_attributes.inject({}) do |results, key_and_value|
145
161
  results.merge! key_and_value.first.to_sym => key_and_value.last
146
162
  end
147
163
  end
164
+
165
+ def builds_returned(response)
166
+ return [] if response["builds"].nil? || response["builds"].empty?
167
+ return [] if response["builds"]["build"].nil? || response["builds"]["build"].empty?
168
+ [response["builds"]["build"]].flatten
169
+ end
148
170
  end
149
171
  end
150
172
  end
@@ -10,6 +10,10 @@ module CodeFumes
10
10
  puts "NOTE: Sending all requests & data to non-production server! (#{API.base_uri})"
11
11
  end
12
12
 
13
+ def issuing_build_command?(command)
14
+ command && command.name.to_sym == :build
15
+ end
16
+
13
17
  def issue_project_commands(message, public_keys, &block)
14
18
  public_keys.each do |public_key|
15
19
  print "#{message}...'#{public_key}': "
@@ -50,5 +54,9 @@ module CodeFumes
50
54
  def open_in_browser(url, &block)
51
55
  has_launchy? {Launchy::Browser.new.visit url}
52
56
  end
57
+
58
+ def multiple_build_states?(options)
59
+ options[:start] && options[:finished]
60
+ end
53
61
  end
54
62
  end
@@ -9,12 +9,18 @@ module CodeFumes
9
9
  class UnknownProjectError < StandardError #:nodoc:
10
10
  end
11
11
 
12
+ class InvalidCommandSyntax < StandardError #:nodoc:
13
+ end
14
+
12
15
  class NoUserApiKeyError < ArgumentError #:nodoc:
13
16
  end
14
17
 
15
18
  class NoApiKeySpecified < ArgumentError #:nodoc:
16
19
  end
17
20
 
21
+ class InvalidBuildState < ArgumentError #:nodoc:
22
+ end
23
+
18
24
  class MissingLaunchyGem < Gem::LoadError #:nodoc:
19
25
  end
20
26
  end
@@ -1,10 +1,14 @@
1
- module ExitCodes
2
- SUCCESS = 0
3
- UNSUPPORTED_SCM = 1
4
- PROJECT_NOT_FOUND = 2
5
- NO_USER_CREDENTIALS = 3
6
- INCORRECT_USER_CREDENTIALS = 4
7
- NO_API_KEY_SPECIFIED = 5
8
- MISSING_DEPENDENCY = 6
9
- UNKNOWN = 100
1
+ module CodeFumes
2
+ module ExitCodes
3
+ SUCCESS = 0
4
+ UNSUPPORTED_SCM = 1
5
+ PROJECT_NOT_FOUND = 2
6
+ NO_USER_CREDENTIALS = 3
7
+ INCORRECT_USER_CREDENTIALS = 4
8
+ NO_API_KEY_SPECIFIED = 5
9
+ MISSING_DEPENDENCY = 6
10
+ INVALID_BUILD_STATE = 7
11
+ INVALID_COMMAND_SYNTAX = 8
12
+ UNKNOWN = 100
13
+ end
10
14
  end
@@ -14,7 +14,7 @@ describe "API::Build" do
14
14
  @build = Build.new(@commit, @build_name, @state, {:started_at => @started_at})
15
15
  end
16
16
 
17
- describe "save" do
17
+ describe "#save" do
18
18
  it "sets basic auth with the public and private key" do
19
19
  @build.stub!(:exists?).and_return(false)
20
20
  register_create_uri(["401", "Unauthorized"], "")
@@ -26,6 +26,22 @@ describe "API::Build" do
26
26
  @build.save
27
27
  end
28
28
 
29
+ it "raises an exception when an invalid state is specified" do
30
+ lambda {
31
+ setup_fixture_base
32
+ @build.state = 'invalid_state'
33
+ @build.save
34
+ }.should raise_error(Errors::InvalidBuildState)
35
+ end
36
+
37
+ it "does not raise an InvalidBuildState exception when a valid state is specified" do
38
+ lambda {
39
+ setup_fixture_base
40
+ @build.state = Build::VALID_BUILD_RESULT_STATES.first
41
+ @build.save
42
+ }.should_not raise_error(Errors::InvalidBuildState)
43
+ end
44
+
29
45
  context "when it's a new build for the specified commit" do
30
46
  before(:each) do
31
47
  @build.stub!(:exists?).and_return(false)
@@ -70,7 +86,7 @@ describe "API::Build" do
70
86
  end
71
87
  end
72
88
 
73
- describe "find" do
89
+ describe "#find" do
74
90
  before(:each) do
75
91
  setup_fixture_base
76
92
  setup_build_fixtures
@@ -89,7 +105,7 @@ describe "API::Build" do
89
105
  end
90
106
  end
91
107
 
92
- describe "destroy" do
108
+ describe "#destroy" do
93
109
  before(:each) do
94
110
  setup_fixture_base
95
111
  setup_build_fixtures
@@ -106,4 +122,20 @@ describe "API::Build" do
106
122
  @build.destroy.should be_false
107
123
  end
108
124
  end
125
+
126
+ describe "#new" do
127
+ it "raises an exception when an invalid state is specified" do
128
+ lambda {
129
+ setup_fixture_base
130
+ Build.new(@commit, @build_name, 'invalid_state')
131
+ }.should raise_error(Errors::InvalidBuildState)
132
+ end
133
+
134
+ it "does not raise an InvalidBuildState exception when a valid state is specified" do
135
+ lambda {
136
+ setup_fixture_base
137
+ Build.new(@commit, @build_name, Build::VALID_BUILD_RESULT_STATES.first)
138
+ }.should_not raise_error(Errors::InvalidBuildState)
139
+ end
140
+ end
109
141
  end