codefumes 0.1.10 → 0.2.0
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.
- data/Gemfile +19 -0
- data/Gemfile.lock +135 -0
- data/History.txt +12 -0
- data/LICENSE +20 -0
- data/Manifest.txt +40 -19
- data/README.txt +11 -29
- data/Rakefile +15 -10
- data/bin/fumes +214 -0
- data/config/website.yml +2 -0
- data/cucumber.yml +2 -0
- data/features/claiming_a_project.feature +46 -0
- data/features/deleting_a_project.feature +32 -0
- data/features/releasing_a_project.feature +50 -0
- data/features/step_definitions/cli_steps.rb +98 -0
- data/features/step_definitions/common_steps.rb +168 -0
- data/features/step_definitions/filesystem_steps.rb +19 -0
- data/features/storing_user_api_key.feature +41 -0
- data/features/support/common.rb +29 -0
- data/features/support/env.rb +24 -0
- data/features/support/matchers.rb +11 -0
- data/features/synchronizing_repository_with_project.feature +33 -0
- data/lib/codefumes.rb +10 -8
- data/lib/codefumes/api.rb +20 -11
- data/lib/codefumes/api/build.rb +139 -0
- data/lib/codefumes/api/claim.rb +74 -0
- data/lib/codefumes/api/commit.rb +150 -0
- data/lib/codefumes/api/payload.rb +93 -0
- data/lib/codefumes/api/project.rb +158 -0
- data/lib/codefumes/cli_helpers.rb +54 -0
- data/lib/codefumes/config_file.rb +3 -2
- data/lib/codefumes/errors.rb +21 -0
- data/lib/codefumes/exit_codes.rb +10 -0
- data/lib/codefumes/harvester.rb +113 -0
- data/lib/codefumes/quick_build.rb +43 -0
- data/lib/codefumes/quick_metric.rb +20 -0
- data/lib/codefumes/source_control.rb +137 -0
- data/lib/integrity_notifier/codefumes.haml +11 -0
- data/lib/integrity_notifier/codefumes.rb +62 -0
- data/spec/codefumes/{build_spec.rb → api/build_spec.rb} +14 -24
- data/spec/codefumes/{claim_spec.rb → api/claim_spec.rb} +42 -3
- data/spec/codefumes/{commit_spec.rb → api/commit_spec.rb} +34 -24
- data/spec/codefumes/api/payload_spec.rb +148 -0
- data/spec/codefumes/api/project_spec.rb +286 -0
- data/spec/codefumes/api_spec.rb +38 -15
- data/spec/codefumes/config_file_spec.rb +69 -13
- data/spec/codefumes/harvester_spec.rb +118 -0
- data/spec/codefumes/source_control_spec.rb +199 -0
- data/spec/codefumes_service_helpers.rb +23 -19
- data/spec/fixtures/sample_project_dirs/no_scm/description +4 -0
- data/spec/spec_helper.rb +1 -0
- data/tasks/cucumber.rake +11 -0
- metadata +145 -60
- data/bin/cf_claim_project +0 -9
- data/bin/cf_release_project +0 -10
- data/bin/cf_store_credentials +0 -10
- data/lib/cf_claim_project/cli.rb +0 -95
- data/lib/cf_release_project/cli.rb +0 -76
- data/lib/cf_store_credentials/cli.rb +0 -50
- data/lib/codefumes/build.rb +0 -131
- data/lib/codefumes/claim.rb +0 -57
- data/lib/codefumes/commit.rb +0 -144
- data/lib/codefumes/payload.rb +0 -103
- data/lib/codefumes/project.rb +0 -129
- data/spec/cf_claim_project/cli_spec.rb +0 -17
- data/spec/cf_release_project/cli_spec.rb +0 -41
- data/spec/cf_store_credentials/cli_spec.rb +0 -28
- data/spec/codefumes/payload_spec.rb +0 -155
- data/spec/codefumes/project_spec.rb +0 -274
@@ -0,0 +1,29 @@
|
|
1
|
+
module CommonHelpers
|
2
|
+
def in_tmp_folder(&block)
|
3
|
+
FileUtils.chdir(@tmp_root, &block)
|
4
|
+
end
|
5
|
+
|
6
|
+
def in_project_folder(&block)
|
7
|
+
project_folder = @active_project_folder || @tmp_root
|
8
|
+
FileUtils.chdir(project_folder, &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def in_home_folder(&block)
|
12
|
+
FileUtils.chdir(@home_path, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def force_local_lib_override(project_name = @project_name)
|
16
|
+
rakefile = File.read(File.join(project_name, 'Rakefile'))
|
17
|
+
File.open(File.join(project_name, 'Rakefile'), "w+") do |f|
|
18
|
+
f << "$:.unshift('#{@lib_path}')\n"
|
19
|
+
f << rakefile
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def setup_active_project_folder project_name
|
24
|
+
@active_project_folder = File.join(@tmp_root, project_name)
|
25
|
+
@project_name = project_name
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
World(CommonHelpers)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../../lib/codefumes"
|
2
|
+
|
3
|
+
gem 'cucumber'
|
4
|
+
require 'cucumber'
|
5
|
+
gem 'rspec'
|
6
|
+
require 'spec'
|
7
|
+
require 'spec/stubs/cucumber'
|
8
|
+
|
9
|
+
include CodeFumes
|
10
|
+
|
11
|
+
gem 'aruba'
|
12
|
+
require 'aruba'
|
13
|
+
|
14
|
+
Before do
|
15
|
+
@tmp_root = File.dirname(__FILE__) + "/../../tmp"
|
16
|
+
@home_path = File.expand_path(File.join(@tmp_root, "home"))
|
17
|
+
@lib_path = File.expand_path(File.dirname(__FILE__) + "/../../lib")
|
18
|
+
@bin_path = File.expand_path(File.dirname(__FILE__) + "/../../bin")
|
19
|
+
FileUtils.rm_rf @tmp_root
|
20
|
+
FileUtils.mkdir_p @home_path
|
21
|
+
ENV['HOME'] = @home_path
|
22
|
+
ENV['CODEFUMES_CONFIG_FILE'] = File.expand_path(File.join(@tmp_root, "codefumes_config_file"))
|
23
|
+
ENV['FUMES_ENV'] = ENV['FUMES_ENV'] || "test"
|
24
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Matchers
|
2
|
+
def contain(expected)
|
3
|
+
simple_matcher("contain #{expected.inspect}") do |given, matcher|
|
4
|
+
matcher.failure_message = "expected #{given.inspect} to contain #{expected.inspect}"
|
5
|
+
matcher.negative_failure_message = "expected #{given.inspect} not to contain #{expected.inspect}"
|
6
|
+
given.index expected
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
World(Matchers)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
Feature: Synchronizing a repository with CodeFumes
|
2
|
+
Keeping a CodeFumes project synchronized with a project's development
|
3
|
+
is a fundamental feature of the site/service. Synchronizing this data must
|
4
|
+
be as simple, quick, and reliable as possible in order to provide value to
|
5
|
+
the users of the site.
|
6
|
+
|
7
|
+
Scenario: Unsupported repository type
|
8
|
+
When I run "#{@bin_path}/fumes sync"
|
9
|
+
Then it should fail with:
|
10
|
+
"""
|
11
|
+
Unsupported
|
12
|
+
"""
|
13
|
+
And the exit status should be 1
|
14
|
+
|
15
|
+
Scenario: Successful synchronization
|
16
|
+
Given I have cloned 1 project
|
17
|
+
When I synchronize the project
|
18
|
+
Then the exit status should be 0
|
19
|
+
And the output should contain "Successfully saved"
|
20
|
+
And the output should contain "Visit http://"
|
21
|
+
|
22
|
+
Scenario: Providing feedback when data is being sent to a non-production server
|
23
|
+
Given I have cloned 1 project
|
24
|
+
When I synchronize the project
|
25
|
+
Then the output should contain "non-production"
|
26
|
+
And the output should contain "test.codefumes.com"
|
27
|
+
And the exit status should be 0
|
28
|
+
|
29
|
+
Scenario: Specifying a custom, but non-existant public/private key combination
|
30
|
+
Given I have cloned 1 project
|
31
|
+
And I cd to "project_1/"
|
32
|
+
When I run "#{@bin_path}/fumes sync -p non-existant-pubkey -a non-existant-privkey"
|
33
|
+
And the exit status should be 2
|
data/lib/codefumes.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
-
require '
|
2
|
-
require 'chronic'
|
1
|
+
require 'grit'
|
3
2
|
|
4
3
|
require 'codefumes/api'
|
5
|
-
require 'codefumes/build'
|
6
|
-
require 'codefumes/claim'
|
7
|
-
require 'codefumes/commit'
|
8
4
|
require 'codefumes/config_file'
|
9
|
-
require 'codefumes/
|
10
|
-
require 'codefumes/
|
5
|
+
require 'codefumes/errors'
|
6
|
+
require 'codefumes/exit_codes'
|
7
|
+
require 'codefumes/harvester.rb'
|
8
|
+
require 'codefumes/quick_build.rb'
|
9
|
+
require 'codefumes/quick_metric.rb'
|
10
|
+
require 'codefumes/source_control.rb'
|
11
|
+
|
12
|
+
include CodeFumes::API
|
11
13
|
|
12
14
|
module CodeFumes
|
13
|
-
VERSION = '0.
|
15
|
+
VERSION = '0.2.0' unless defined?(CodeFumes::VERSION)
|
14
16
|
end
|
data/lib/codefumes/api.rb
CHANGED
@@ -1,7 +1,16 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'chronic'
|
3
|
+
|
4
|
+
require 'codefumes/api/build'
|
5
|
+
require 'codefumes/api/claim'
|
6
|
+
require 'codefumes/api/commit'
|
7
|
+
require 'codefumes/api/payload'
|
8
|
+
require 'codefumes/api/project'
|
9
|
+
|
1
10
|
module CodeFumes
|
2
|
-
|
11
|
+
module API
|
3
12
|
include HTTParty
|
4
|
-
|
13
|
+
base_uri 'http://codefumes.com/api/v1/xml'
|
5
14
|
format :xml
|
6
15
|
|
7
16
|
BASE_URIS = {
|
@@ -10,16 +19,16 @@ module CodeFumes
|
|
10
19
|
:local => 'http://codefumes.com.local/api/v1/xml'
|
11
20
|
} #:nodoc:
|
12
21
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
#
|
17
|
-
# +:local+ is also technically supported, but provided for local
|
18
|
-
# testing and likely only useful for CodeFumes.com developers.
|
19
|
-
def self.mode(mode)
|
20
|
-
base_uri(BASE_URIS[mode]) if BASE_URIS[mode]
|
22
|
+
def self.mode=(mode)
|
23
|
+
return if mode.to_s.empty?
|
24
|
+
base_uri(BASE_URIS[mode.to_sym]) if BASE_URIS[mode.to_sym]
|
21
25
|
end
|
22
26
|
|
23
|
-
mode(
|
27
|
+
def self.mode?(mode)
|
28
|
+
return false if mode.nil?
|
29
|
+
base_uri == BASE_URIS[mode.to_sym]
|
30
|
+
end
|
24
31
|
end
|
25
32
|
end
|
33
|
+
|
34
|
+
CodeFumes::API.mode= ENV['FUMES_ENV']
|
@@ -0,0 +1,139 @@
|
|
1
|
+
module CodeFumes
|
2
|
+
module API
|
3
|
+
# Represents a specific instance of tests running on
|
4
|
+
# a continuous integration server. Builds have a name and are
|
5
|
+
# associated with # a specific Commit of a Project and can track
|
6
|
+
# the current status (running, failed, success) and the
|
7
|
+
# start & end times of the Build process.
|
8
|
+
class Build
|
9
|
+
attr_reader :created_at, :api_uri, :identifier, :commit, :project
|
10
|
+
attr_accessor :started_at, :ended_at, :state, :name
|
11
|
+
|
12
|
+
# Initializes new instance of a Build.
|
13
|
+
#
|
14
|
+
# * commit - Instance of CodeFumes::Commit to associate the Build with
|
15
|
+
# * name - A name for the build ('ie7', 'specs', etc.)
|
16
|
+
# * state - Current state of the build (defaults: 'running')
|
17
|
+
# * valid values: 'running', 'failed', 'successful'
|
18
|
+
# * options - Hash of additional options. Accepts the following:
|
19
|
+
# * :started_at - Time the build started
|
20
|
+
# * :ended_at - Time the build completed (defaults to nil)
|
21
|
+
def initialize(commit, name, state = 'running', options = {})
|
22
|
+
@commit = commit
|
23
|
+
@project = commit.project
|
24
|
+
@name = name
|
25
|
+
@state = state.to_s
|
26
|
+
@started_at = options[:started_at] || options['started_at'] || Time.now
|
27
|
+
@ended_at = options[:ended_at] || options['ended_at']
|
28
|
+
end
|
29
|
+
|
30
|
+
# Overrides existing attributes with those supplied in +options+. This
|
31
|
+
# simplifies the process of updating an object's state when given a response
|
32
|
+
# from the CodeFumes API.
|
33
|
+
#
|
34
|
+
# Valid options are:
|
35
|
+
# * identifier
|
36
|
+
# * name
|
37
|
+
# * state
|
38
|
+
# * started_at
|
39
|
+
# * ended_at
|
40
|
+
# * api_uri
|
41
|
+
#
|
42
|
+
# Returns +self+
|
43
|
+
def reinitialize_from_hash!(options = {})
|
44
|
+
@identifier = options[:identifier] || options['identifier']
|
45
|
+
@name = options[:name] || options['name']
|
46
|
+
@state = options[:state] || options['state']
|
47
|
+
@api_uri = options[:api_uri] || options['api_uri']
|
48
|
+
@started_at = options[:started_at] || options['started_at']
|
49
|
+
@ended_at = options[:ended_at] || options['ended_at']
|
50
|
+
@created_at = options[:created_at] || options['created_at']
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
# Saves the Build instance to CodeFumes.com
|
55
|
+
#
|
56
|
+
# Returns +true+ if successful
|
57
|
+
#
|
58
|
+
# Returns +false+ if request fails
|
59
|
+
# ---
|
60
|
+
# TODO: Make this consistent w/ other class' create/update handling
|
61
|
+
def save
|
62
|
+
response = exists? ? update : create
|
63
|
+
|
64
|
+
case response.code
|
65
|
+
when 201,200
|
66
|
+
reinitialize_from_hash!(response['build'])
|
67
|
+
true
|
68
|
+
else
|
69
|
+
false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Searches website for Build with the supplied identifier.
|
74
|
+
#
|
75
|
+
# Returns a Build instance if the Build exists and is available,
|
76
|
+
# to the user making the request.
|
77
|
+
#
|
78
|
+
# Returns +nil+ in all other cases.
|
79
|
+
def self.find(commit, build_name)
|
80
|
+
project = commit.project
|
81
|
+
uri = "/projects/#{project.public_key}/commits/#{commit.identifier}/builds/#{build_name}"
|
82
|
+
|
83
|
+
response = API.get(uri)
|
84
|
+
|
85
|
+
case response.code
|
86
|
+
when 200
|
87
|
+
build_params = response["build"] || {}
|
88
|
+
name = build_params["name"]
|
89
|
+
state = build_params["state"]
|
90
|
+
build = Build.new(commit, name, state)
|
91
|
+
build.reinitialize_from_hash!(build_params)
|
92
|
+
else
|
93
|
+
nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
# Returns true if the request was successful
|
99
|
+
#
|
100
|
+
# Returns +false+ in all other cases.
|
101
|
+
def destroy
|
102
|
+
uri = "/projects/#{@project.public_key}/commits/#{@commit.identifier}/builds/#{@name}"
|
103
|
+
auth_args = {:username => @project.public_key, :password => @project.private_key}
|
104
|
+
|
105
|
+
response = API.delete(uri, :basic_auth => auth_args)
|
106
|
+
|
107
|
+
case response.code
|
108
|
+
when 200 : true
|
109
|
+
else false
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
# Verifies existence of Build on website.
|
115
|
+
#
|
116
|
+
# Returns +true+ if a build with the specified identifier or name is associated with
|
117
|
+
# the specified project/commit
|
118
|
+
#
|
119
|
+
# Returns +false+ if the public key of the Project is not available.
|
120
|
+
def exists?
|
121
|
+
!self.class.find(commit, name).nil?
|
122
|
+
end
|
123
|
+
|
124
|
+
# Saves a new build (makes POST request)
|
125
|
+
def create
|
126
|
+
API.post("/projects/#{project.public_key}/commits/#{commit.identifier}/builds", :query => {:build => standard_content_hash}, :basic_auth => {:username => project.public_key, :password => project.private_key})
|
127
|
+
end
|
128
|
+
|
129
|
+
# Updates an existing build (makes PUT request)
|
130
|
+
def update
|
131
|
+
API.put("/projects/#{project.public_key}/commits/#{commit.identifier}/builds/#{name}", :query => {:build => standard_content_hash}, :basic_auth => {:username => project.public_key, :password => project.private_key})
|
132
|
+
end
|
133
|
+
|
134
|
+
def standard_content_hash
|
135
|
+
{:name => name,:started_at => started_at, :ended_at => ended_at, :state => state}
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module CodeFumes
|
2
|
+
module API
|
3
|
+
class Claim
|
4
|
+
attr_accessor :created_at
|
5
|
+
SUPPORTED_VISIBILITIES = [:public, :private]
|
6
|
+
|
7
|
+
# Attempts to claim the specified Project instance using the
|
8
|
+
# supplied API key.
|
9
|
+
#
|
10
|
+
# +visibility+ defaults to +:public+. Valid options are +public+
|
11
|
+
# and +private+.
|
12
|
+
#
|
13
|
+
# Similar to Project#claim, but more explicit.
|
14
|
+
#
|
15
|
+
# Returns +true+ if the request is successful, or if the project
|
16
|
+
# was already owned by the user associated with the privided API
|
17
|
+
# key.
|
18
|
+
#
|
19
|
+
# Returns +false+ in all other cases.
|
20
|
+
def self.create(project, api_key, visibility = :public)
|
21
|
+
validate_api_key(api_key)
|
22
|
+
validate_visibility(visibility)
|
23
|
+
|
24
|
+
auth_args = {:username => project.public_key, :password => project.private_key}
|
25
|
+
|
26
|
+
uri = "/projects/#{project.public_key}/claim"
|
27
|
+
response = API.put(uri, :query => {:api_key => api_key, :visibility => visibility}, :basic_auth => auth_args)
|
28
|
+
|
29
|
+
case response.code
|
30
|
+
when 200 : true
|
31
|
+
else false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Removes a claim on the specified Project instance using the
|
36
|
+
# supplied API key, releasing ownership. If the project was a
|
37
|
+
# "private" project, this method will convert it to "public".
|
38
|
+
#
|
39
|
+
# Returns true if the request was successful or there was not
|
40
|
+
# an existing owner (the action is idempotent).
|
41
|
+
#
|
42
|
+
# Returns +false+ in all other cases.
|
43
|
+
def self.destroy(project, api_key)
|
44
|
+
validate_api_key(api_key)
|
45
|
+
|
46
|
+
auth_args = {:username => project.public_key, :password => project.private_key}
|
47
|
+
|
48
|
+
uri = "/projects/#{project.public_key}/claim"
|
49
|
+
response = API.delete(uri, :query => {:api_key => api_key}, :basic_auth => auth_args)
|
50
|
+
|
51
|
+
case response.code
|
52
|
+
when 200 : true
|
53
|
+
else false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def self.validate_api_key(api_key)
|
59
|
+
if api_key.nil? || api_key.empty?
|
60
|
+
msg = "Invalid user api key provided. (provided: '#{api_key}')"
|
61
|
+
raise(Errors::NoUserApiKeyError, msg)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.validate_visibility(visibility)
|
66
|
+
unless SUPPORTED_VISIBILITIES.include?(visibility.to_sym)
|
67
|
+
msg = "Unsupported visibility supplied (#{visibility.to_s}). "
|
68
|
+
msg << "Valid options are: #{SUPPORTED_VISIBILITIES.join(', ')}"
|
69
|
+
raise ArgumentError, msg
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
module CodeFumes
|
2
|
+
module API
|
3
|
+
# Similar to a revision control system, a Commit encompasses a set of
|
4
|
+
# changes to a codebase, who made them, when said changes were applied
|
5
|
+
# to the previous revision of codebase, et cetera.
|
6
|
+
#
|
7
|
+
# A Commit has a concept of 'standard attributes' which will always be
|
8
|
+
# present in a response from CodeFumes.com[http://codefumes.com], such
|
9
|
+
# as the +identifier+, +author+, and +commit_message+ (see the list of
|
10
|
+
# attributes for a comprehensive listing). In addition to this, users
|
11
|
+
# are able to associate 'custom attributes' to a Commit, allowing
|
12
|
+
# users to link any number of attributes with a commit identifier and
|
13
|
+
# easily retrieve them later.
|
14
|
+
#
|
15
|
+
# One thing to note about Commit objects is that they are read-only.
|
16
|
+
# To associate metrics with a Commit object, a Payload object should
|
17
|
+
# be created and saved. Refer to the Payload documentation for more
|
18
|
+
# information.
|
19
|
+
class Commit
|
20
|
+
attr_reader :identifier, :author_name, :author_email, :committer_name,
|
21
|
+
:committer_email, :short_message, :message,:committed_at,
|
22
|
+
:authored_at, :uploaded_at, :api_uri, :parent_identifiers,
|
23
|
+
:line_additions, :line_deletions, :line_total,
|
24
|
+
:affected_file_count, :custom_attributes, :project
|
25
|
+
alias_method :id, :identifier
|
26
|
+
alias_method :sha, :identifier
|
27
|
+
|
28
|
+
# Instantiates a new Commit object
|
29
|
+
#
|
30
|
+
# * +identifier+ - the revision number of the commit (git commit sha, svn version, etc)
|
31
|
+
#
|
32
|
+
# Accepts a Hash of options, including:
|
33
|
+
# * author_email
|
34
|
+
# * author_name
|
35
|
+
# * committer_email
|
36
|
+
# * committer_name
|
37
|
+
# * short_message
|
38
|
+
# * message
|
39
|
+
# * committed_at
|
40
|
+
# * authored_at
|
41
|
+
# * uploaded_at
|
42
|
+
# * api_uri
|
43
|
+
# * parent_identifiers
|
44
|
+
# * line_additions
|
45
|
+
# * line_deletions
|
46
|
+
# * line_total
|
47
|
+
# * affected_file_count
|
48
|
+
# * custom_attributes
|
49
|
+
#
|
50
|
+
# +custom_attributes+ should be a Hash of attribute_name/value
|
51
|
+
# pairs associated with the commit. All other attributes are
|
52
|
+
# expected to be String values, other than +committed_at+ and
|
53
|
+
# +authored_at+, which are expected to be DateTime objects.
|
54
|
+
# Technically speaking, you could pass anything you wanted into
|
55
|
+
# the fields, but when using with the CodeFumes API, the attribute
|
56
|
+
# values will be of the type String, DateTime, or Hash.
|
57
|
+
def initialize(project, identifier, options = {})
|
58
|
+
@project = project
|
59
|
+
@identifier = identifier
|
60
|
+
@author_email = options[:author_email] || options["author_email"]
|
61
|
+
@author_name = options[:author_name] || options["author_name"]
|
62
|
+
@committer_email = options[:committer_email] || options["committer_email"]
|
63
|
+
@committer_name = options[:committer_name] || options["committer_name"]
|
64
|
+
@short_message = options[:short_message] || options["short_message"]
|
65
|
+
@message = options[:message] || options["message"]
|
66
|
+
@committed_at = options[:committed_at] || options["committed_at"]
|
67
|
+
@authored_at = options[:authored_at] || options["authored_at"]
|
68
|
+
@uploaded_at = options[:uploaded_at] || options["uploaded_at"]
|
69
|
+
@api_uri = options[:api_uri] || options["api_uri"]
|
70
|
+
@parent_identifiers = options[:parent_identifiers] || options["parent_identifiers"]
|
71
|
+
@line_additions = options[:line_additions] || options["line_additions"]
|
72
|
+
@line_deletions = options[:line_deletions] || options["line_deletions"]
|
73
|
+
@line_total = options[:line_total] || options["line_total"]
|
74
|
+
@affected_file_count = options[:affected_file_count] || options["affected_file_count"]
|
75
|
+
@custom_attributes = options[:custom_attributes] || options["custom_attributes"] || {}
|
76
|
+
convert_custom_attributes_keys_to_symbols
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns the name of the author and the email associated
|
80
|
+
# with the commit in a string formatted as:
|
81
|
+
# "Name [email_address]"
|
82
|
+
# (ie: "John Doe [jdoe@example.com]")
|
83
|
+
def author
|
84
|
+
"#{author_name} [#{author_email}]"
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns the name of the committer and the email associated
|
88
|
+
# with the commit in a string formatted as:
|
89
|
+
# "Name [email_address]"
|
90
|
+
# (ie: "John Doe [jdoe@example.com]")
|
91
|
+
def committer
|
92
|
+
"#{committer_name} [#{committer_email}]"
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns the Commit object associated with the supplied identifier.
|
96
|
+
# Returns nil if the identifier is not found.
|
97
|
+
def self.find(project, identifier)
|
98
|
+
response = API.get("/projects/#{project.public_key}/commits/#{identifier}")
|
99
|
+
case response.code
|
100
|
+
when 200
|
101
|
+
return nil if response["commit"].empty?
|
102
|
+
new(project, response["commit"].delete("identifier"), response["commit"])
|
103
|
+
else
|
104
|
+
nil
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Returns a collection of commits associated with the specified
|
109
|
+
# Project public key.
|
110
|
+
def self.all(project)
|
111
|
+
response = API.get("/projects/#{project.public_key}/commits")
|
112
|
+
case response.code
|
113
|
+
when 200
|
114
|
+
return [] if response["commits"].empty? || response["commits"]["commit"].nil?
|
115
|
+
response["commits"]["commit"].map do |commit_data|
|
116
|
+
new(commit_data.delete("identifier"), commit_data)
|
117
|
+
end
|
118
|
+
else
|
119
|
+
nil
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns the most recent commit associated with the specified
|
124
|
+
# Project public key.
|
125
|
+
def self.latest(project)
|
126
|
+
response = API.get("/projects/#{project.public_key}/commits/latest")
|
127
|
+
case response.code
|
128
|
+
when 200
|
129
|
+
new(project, response["commit"].delete("identifier"), response["commit"])
|
130
|
+
else
|
131
|
+
nil
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns the commit identifier of the most recent commit of with
|
136
|
+
# the specified Project public key.
|
137
|
+
def self.latest_identifier(project)
|
138
|
+
latest_commit = latest(project)
|
139
|
+
latest_commit.nil? ? nil : latest_commit.identifier
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
def convert_custom_attributes_keys_to_symbols
|
144
|
+
@custom_attributes = @custom_attributes.inject({}) do |results, key_and_value|
|
145
|
+
results.merge! key_and_value.first.to_sym => key_and_value.last
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|