taskmapper-github 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,129 @@
1
+ module TaskMapper::Provider
2
+ module Github
3
+ # Ticket class for taskmapper-github
4
+
5
+ class Ticket < TaskMapper::Provider::Base::Ticket
6
+
7
+ @@allowed_states = %w{open close}
8
+ attr_accessor :prefix_options
9
+ # declare needed overloaded methods here
10
+
11
+ def initialize(*object)
12
+ if object.first
13
+ object = object.first
14
+ unless object.is_a? Hash
15
+ hash = {:id => object.number,
16
+ :status => object.state,
17
+ :description => object.body,
18
+ :user => object.user,
19
+ :project_id => object.project_id}
20
+ else
21
+ hash = object
22
+ end
23
+ super hash
24
+ end
25
+ end
26
+
27
+ def id
28
+ self.number
29
+ end
30
+
31
+ def status
32
+ self.state
33
+ end
34
+
35
+ def description
36
+ self.body
37
+ end
38
+
39
+ def description=(val)
40
+ self.body = val
41
+ end
42
+
43
+ def author
44
+ self.user.respond_to?('login') ? self.user.login : self.user
45
+ end
46
+
47
+ def requestor
48
+ self.user.respond_to?('login') ? self.user.login : self.user
49
+ end
50
+
51
+ def assignee
52
+ self.user.respond_to?('login') ? self.user.login : self.user
53
+ end
54
+
55
+ def self.find_by_id(project_id, number)
56
+ issue = TaskMapper::Provider::Github.api.issue(project_id, number)
57
+ issue.merge!(:project_id => project_id)
58
+ self.new issue
59
+ end
60
+
61
+ def self.find(project_id, *options)
62
+ if options[0].empty?
63
+ self.find_all(project_id)
64
+ elsif options[0].first.is_a? Array
65
+ options[0].first.collect { |number| self.find_by_id(project_id, number) }
66
+ elsif options[0].first.is_a? Hash
67
+ self.find_by_attributes(project_id, options[0].first)
68
+ end
69
+ end
70
+
71
+ def self.find_by_attributes(project_id, attributes = {})
72
+ issues = self.find_all(project_id)
73
+ search_by_attribute(issues, attributes)
74
+ end
75
+
76
+ def self.find_all(project_id)
77
+ issues = []
78
+ issues += TaskMapper::Provider::Github.api.issues(project_id)
79
+ issues += TaskMapper::Provider::Github.api.issues(project_id, {:state => "closed"})
80
+ issues.collect do |issue|
81
+ issue.merge!(:project_id => project_id)
82
+ Ticket.new issue
83
+ end
84
+ end
85
+
86
+ def self.open(project_id, *options)
87
+ ticket_hash = options.first
88
+ body = ticket_hash.delete(:description)
89
+ title = ticket_hash.delete(:title)
90
+ new_issue = TaskMapper::Provider::Github.api.create_issue(project_id, title, body, options.first)
91
+ new_issue.merge!(:project_id => project_id)
92
+ self.new new_issue
93
+ end
94
+
95
+ def created_at
96
+ begin
97
+ Time.parse(self[:created_at])
98
+ rescue
99
+ self[:created_at]
100
+ end
101
+ end
102
+
103
+ def updated_at
104
+ begin
105
+ Time.parse(self[:updated_at])
106
+ rescue
107
+ self[:updated_at]
108
+ end
109
+ end
110
+
111
+ def save
112
+ TaskMapper::Provider::Github.api.update_issue(project_id, number, title, description)
113
+ true
114
+ end
115
+
116
+ def reopen
117
+ Ticket.new(project_id, TaskMapper::Provider::Github.api.reopen_issue(project_id, number))
118
+ end
119
+
120
+ def close
121
+ Ticket.new(project_id, TaskMapper::Provider::Github.api.close_issue(project_id, number))
122
+ end
123
+
124
+ def comment!(attributes)
125
+ Comment.create(project_id, number, attributes)
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,8 @@
1
+ #require YOUR_PROVIDER_API
2
+ require 'octokit'
3
+ require 'active_support/core_ext/string'
4
+ require 'net/http'
5
+
6
+ %w{ github ticket project comment }.each do |f|
7
+ require File.dirname(__FILE__) + '/provider/' + f + '.rb';
8
+ end
@@ -0,0 +1,44 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe TaskMapper::Provider::Github::Comment do
4
+
5
+ before(:each) do
6
+ @github = TaskMapper.new(:github, {:login => 'taskmapper-user', :password => 'Tm123456'})
7
+ stub_get('https://taskmapper-user:Tm123456@github.com/api/v2/json/organizations/repositories', 'repositories.json')
8
+ stub_get('https://taskmapper-user:Tm123456@api.github.com/repos/taskmapper-user/tmtest-repo', 'project.json')
9
+ stub_get('https://taskmapper-user:Tm123456@api.github.com/repos/taskmapper-user/tmtest-repo/issues','issues.json')
10
+ stub_get('https://taskmapper-user:Tm123456@api.github.com/repos/taskmapper-user/tmtest-repo/issues?state=closed','closed_issues.json')
11
+ stub_get('https://taskmapper-user:Tm123456@api.github.com/repos/taskmapper-user/tmtest-repo/issues/1/comments', 'comments.json')
12
+ stub_post('https://taskmapper-user:Tm123456@api.github.com/repos/taskmapper-user/tmtest-repo/issues/1/comments', 'comments/3951282.json')
13
+ stub_post('https://taskmapper-user:Tm123456@api.github.com/repos/taskmapper-user/tmtest-repo/issues/comments/3951282', 'comments/3951282_update.json')
14
+ @project = @github.project('tmtest-repo')
15
+ @ticket = @project.tickets.first
16
+ @klass = TaskMapper::Provider::Github::Comment
17
+ @api = Octokit::Client
18
+ end
19
+
20
+ it "should be able to load all comments" do
21
+ comments = @ticket.comments
22
+ comments.should be_an_instance_of(Array)
23
+ comments.first.should be_an_instance_of(@klass)
24
+ comments.first.body.should == "for testing"
25
+ end
26
+
27
+ it "should be able to create a new comment" do
28
+ comment = @ticket.comment!(:body => 'for testing')
29
+ comment.should be_an_instance_of(@klass)
30
+ comment.body.should == 'for testing'
31
+ end
32
+
33
+ #see bug 116 tm-github: Bug Ticket#comments returning comments with weird text in the body
34
+ it "should be able to load a ticket and clean comment body" do
35
+ comments = @ticket.comments.map(&:body).should == ["for testing", "test comment"]
36
+ end
37
+
38
+ it "should be able to update comments" do
39
+ comment = @ticket.comments.first
40
+ comment.body = "updated comment"
41
+ comment.save.should be_true
42
+ end
43
+
44
+ end
@@ -0,0 +1,3 @@
1
+ [
2
+
3
+ ]
@@ -0,0 +1,30 @@
1
+ [
2
+ {
3
+ "url": "https://api.github.com/repos/taskmapper-user/tmtest-repo/issues/comments/3951282",
4
+ "created_at": "2012-02-13T22:49:55Z",
5
+ "body": "for testing",
6
+ "updated_at": "2012-02-13T22:49:55Z",
7
+ "id": 3951282,
8
+ "user": {
9
+ "url": "https://api.github.com/users/taskmapper-user",
10
+ "gravatar_id": "42bd18419413dfbd6e7ec4fefdec94ae",
11
+ "login": "taskmapper-user",
12
+ "avatar_url": "https://secure.gravatar.com/avatar/42bd18419413dfbd6e7ec4fefdec94ae?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png",
13
+ "id": 1434902
14
+ }
15
+ },
16
+ {
17
+ "url": "https://api.github.com/repos/taskmapper-user/tmtest-repo/issues/comments/3951282",
18
+ "created_at": "2012-02-13T22:49:55Z",
19
+ "body": "--- \nbody: test comment\n",
20
+ "updated_at": "2012-02-13T22:49:55Z",
21
+ "id": 3951283,
22
+ "user": {
23
+ "url": "https://api.github.com/users/taskmapper-user",
24
+ "gravatar_id": "42bd18419413dfbd6e7ec4fefdec94ae",
25
+ "login": "taskmapper-user",
26
+ "avatar_url": "https://secure.gravatar.com/avatar/42bd18419413dfbd6e7ec4fefdec94ae?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png",
27
+ "id": 1434902
28
+ }
29
+ }
30
+ ]
@@ -0,0 +1,16 @@
1
+ {
2
+ "url": "https://api.github.com/repos/taskmapper-user/tmtest-repo/issues/comments/3951282",
3
+ "created_at": "2012-02-13T22:49:55Z",
4
+ "body": {
5
+ "body": "for testing"
6
+ },
7
+ "updated_at": "2012-02-13T22:49:55Z",
8
+ "id": 3951282,
9
+ "user": {
10
+ "url": "https://api.github.com/users/taskmapper-user",
11
+ "gravatar_id": "42bd18419413dfbd6e7ec4fefdec94ae",
12
+ "login": "taskmapper-user",
13
+ "avatar_url": "https://secure.gravatar.com/avatar/42bd18419413dfbd6e7ec4fefdec94ae?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png",
14
+ "id": 1434902
15
+ }
16
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "url": "https://api.github.com/repos/taskmapper-user/tmtest-repo/issues/comments/3951282",
3
+ "created_at": "2012-02-13T22:49:55Z",
4
+ "body": "for testing",
5
+ "updated_at": "2012-02-13T22:49:55Z",
6
+ "id": 3951282,
7
+ "user": {
8
+ "url": "https://api.github.com/users/taskmapper-user",
9
+ "gravatar_id": "42bd18419413dfbd6e7ec4fefdec94ae",
10
+ "login": "taskmapper-user",
11
+ "avatar_url": "https://secure.gravatar.com/avatar/42bd18419413dfbd6e7ec4fefdec94ae?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png",
12
+ "id": 1434902
13
+ }
14
+ }
@@ -0,0 +1,32 @@
1
+ [
2
+ {
3
+ "title": "for testing",
4
+ "url": "https://api.github.com/repos/taskmapper-user/tmtest-repo/issues/1",
5
+ "closed_at": null,
6
+ "created_at": "2012-02-13T22:45:27Z",
7
+ "milestone": null,
8
+ "labels": [
9
+
10
+ ],
11
+ "number": 1,
12
+ "body": "",
13
+ "html_url": "https://github.com/taskmapper-user/tmtest-repo/issues/1",
14
+ "updated_at": "2012-02-13T22:49:55Z",
15
+ "comments": 1,
16
+ "state": "open",
17
+ "pull_request": {
18
+ "diff_url": null,
19
+ "patch_url": null,
20
+ "html_url": null
21
+ },
22
+ "assignee": null,
23
+ "id": 3210729,
24
+ "user": {
25
+ "url": "https://api.github.com/users/taskmapper-user",
26
+ "gravatar_id": "42bd18419413dfbd6e7ec4fefdec94ae",
27
+ "login": "taskmapper-user",
28
+ "avatar_url": "https://secure.gravatar.com/avatar/42bd18419413dfbd6e7ec4fefdec94ae?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png",
29
+ "id": 1434902
30
+ }
31
+ }
32
+ ]
@@ -0,0 +1 @@
1
+ {"issue":{"comments":1,"position":1.0,"number":1,"state":"open","updated_at":"2012/02/13 14:49:55 -0800","labels":[],"user":"taskmapper-user","body":"","title":"for testing","html_url":"https://github.com/taskmapper-user/tmtest-repo/issues/1","created_at":"2012/02/13 14:45:27 -0800","votes":0,"gravatar_id":"42bd18419413dfbd6e7ec4fefdec94ae"}}
@@ -0,0 +1 @@
1
+ {"issue":{"comments":1,"position":1.0,"number":1,"state":"open","updated_at":"2012/02/13 14:49:55 -0800","labels":[],"user":"taskmapper-user","body":"","title":"for testing","html_url":"https://github.com/taskmapper-user/tmtest-repo/issues/1","created_at":"2012/02/13 14:45:27 -0800","votes":0,"gravatar_id":"42bd18419413dfbd6e7ec4fefdec94ae"}}
@@ -0,0 +1,34 @@
1
+ {
2
+ "watchers": 1,
3
+ "url": "https://api.github.com/repos/taskmapper-user/tmtest-repo",
4
+ "master_branch": null,
5
+ "created_at": "2012-02-13T22:20:10Z",
6
+ "html_url": "https://github.com/taskmapper-user/tmtest-repo",
7
+ "ssh_url": "git@github.com:taskmapper-user/tmtest-repo.git",
8
+ "description": "",
9
+ "has_wiki": true,
10
+ "clone_url": "https://github.com/taskmapper-user/tmtest-repo.git",
11
+ "forks": 1,
12
+ "fork": false,
13
+ "pushed_at": null,
14
+ "git_url": "git://github.com/taskmapper-user/tmtest-repo.git",
15
+ "mirror_url": null,
16
+ "open_issues": 1,
17
+ "private": false,
18
+ "svn_url": "https://github.com/taskmapper-user/tmtest-repo",
19
+ "homepage": "",
20
+ "size": 0,
21
+ "has_issues": true,
22
+ "updated_at": "2012-02-13T22:20:10Z",
23
+ "owner": {
24
+ "url": "https://api.github.com/users/taskmapper-user",
25
+ "gravatar_id": "42bd18419413dfbd6e7ec4fefdec94ae",
26
+ "login": "taskmapper-user",
27
+ "avatar_url": "https://secure.gravatar.com/avatar/42bd18419413dfbd6e7ec4fefdec94ae?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png",
28
+ "id": 1434902
29
+ },
30
+ "name": "tmtest-repo",
31
+ "id": 3434734,
32
+ "has_downloads": true,
33
+ "language": null
34
+ }
@@ -0,0 +1,34 @@
1
+ [{
2
+ "watchers":"1",
3
+ "url":"https://api.github.com/repos/taskmapper-user/tmtest-repo",
4
+ "created_at":"2012-02-13T22:20:10Z",
5
+ "mirror_url":"null",
6
+ "has_wiki":"true",
7
+ "html_url":"https://github.com/taskmapper-user/tmtest-repo",
8
+ "ssh_url":"git@github.com:taskmapper-user/tmtest-repo.git",
9
+ "description":"",
10
+ "forks":"1",
11
+ "clone_url":"https://github.com/taskmapper-user/tmtest-repo.git",
12
+ "fork":false,
13
+ "open_issues":"1",
14
+ "private":false,
15
+ "homepage":"",
16
+ "size":"0",
17
+ "has_issues":true,
18
+ "master_branch":"null",
19
+ "pushed_at":"null",
20
+ "updated_at":"2012-02-13T22:20:10Z",
21
+ "owner": {
22
+ "url":"https://api.github.com/users/taskmapper-user",
23
+ "avatar_url":"https://secure.gravatar.com/avatar/42bd18419413dfbd6e7ec4fefdec94ae?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png",
24
+ "gravatar_id":"42bd18419413dfbd6e7ec4fefdec94ae",
25
+ "login":"taskmapper-user",
26
+ "id":"1434902"
27
+ },
28
+ "name":"tmtest-repo",
29
+ "has_downloads":true,
30
+ "id":"3434734",
31
+ "git_url":"git://github.com/taskmapper-user/tmtest-repo.git",
32
+ "svn_url":"https://github.com/taskmapper-user/tmtest-repo",
33
+ "language":"null"
34
+ }]
@@ -0,0 +1 @@
1
+ {"repositories":[]}
@@ -0,0 +1,49 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe TaskMapper::Provider::Github::Project do
4
+
5
+ before(:all) do
6
+ @repo_name = "tmtest-repo"
7
+ @returned_repo = "taskmapper-user/tmtest-repo"
8
+ @klass = TaskMapper::Provider::Github::Project
9
+ end
10
+
11
+ before(:each) do
12
+ @github = TaskMapper.new(:github, :login => 'taskmapper-user', :password => 'Tm123456')
13
+ end
14
+
15
+ it "should be able to load all projects" do
16
+ stub_get('https://taskmapper-user:Tm123456@api.github.com/users/taskmapper-user/repos', 'projects.json')
17
+ stub_get('https://taskmapper-user:Tm123456@github.com/api/v2/json/organizations/repositories', 'repositories.json')
18
+ @projects = @github.projects
19
+ @projects.should be_an_instance_of(Array)
20
+ @projects.first.should be_an_instance_of(@klass)
21
+ end
22
+
23
+ it "should be able to load all projects based on an array of name(id)" do
24
+ stub_get('https://taskmapper-user:Tm123456@api.github.com/repos/taskmapper-user/tmtest-repo', 'project.json')
25
+ @projects = @github.projects([@repo_name])
26
+ @projects.should be_an_instance_of(Array)
27
+ @projects.first.should be_an_instance_of(@klass)
28
+ @projects.first.id.should == @returned_repo
29
+ end
30
+
31
+ it "should be able to load a single project based on a single name(id)" do
32
+ @project = @github.projects(@repo_name)
33
+ @project.should be_an_instance_of(@klass)
34
+ @project.id.should == @returned_repo
35
+ end
36
+
37
+ it "should be able to find by name(id)" do
38
+ @project = @github.project(@repo_name)
39
+ @project.should be_an_instance_of(@klass)
40
+ @project.id.should == @returned_repo
41
+ end
42
+
43
+ it "should be able to find by attributes" do
44
+ @projects = @github.projects(:name => 'tmtest-repo')
45
+ @projects.should be_an_instance_of(Array)
46
+ @projects.first.id.should be_eql(@returned_repo)
47
+ end
48
+ end
49
+
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,35 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'rubygems'
5
+ require 'taskmapper'
6
+ require 'active_support/core_ext/string'
7
+ require 'rspec'
8
+ require 'taskmapper-github'
9
+ require 'fakeweb'
10
+
11
+ RSpec.configure do |config|
12
+ config.color_enabled = true
13
+ end
14
+
15
+ FakeWeb.allow_net_connect = false
16
+
17
+ def fixture_file(filename)
18
+ return '' if filename == ''
19
+ file_path = File.expand_path(File.dirname(__FILE__) + '/fixtures/' + filename)
20
+ File.read(file_path)
21
+ end
22
+
23
+
24
+ def stub_request(method, url, filename, status=nil)
25
+ options = {:body => ""}
26
+ options.merge!({:body => fixture_file(filename)}) if filename
27
+ options.merge!({:body => status.last}) if status
28
+ options.merge!({:status => status}) if status
29
+
30
+ FakeWeb.register_uri(method, url, options)
31
+ end
32
+
33
+ def stub_get(*args); stub_request(:get, *args) end
34
+ def stub_post(*args); stub_request(:post, *args) end
35
+ def stub_delete(*args); stub_request(:delete, *args) end