diff --git a/.rspec b/.rspec
new file mode 100644
index 00000000000..4e1e0d2f722
--- /dev/null
+++ b/.rspec
@@ -0,0 +1 @@
+--color
diff --git a/plugins/github_relation/Gemfile b/plugins/github_relation/Gemfile
new file mode 100644
index 00000000000..70688299dda
--- /dev/null
+++ b/plugins/github_relation/Gemfile
@@ -0,0 +1,6 @@
+gem "octokit"
+group :development, :test do
+ gem 'rspec-rails'
+ gem 'debugger'
+ gem 'hashie'
+end
\ No newline at end of file
diff --git a/plugins/github_relation/Gemfile.lock b/plugins/github_relation/Gemfile.lock
new file mode 100644
index 00000000000..36e9e2f3a6d
--- /dev/null
+++ b/plugins/github_relation/Gemfile.lock
@@ -0,0 +1,87 @@
+GEM
+ specs:
+ actionpack (3.2.14)
+ activemodel (= 3.2.14)
+ activesupport (= 3.2.14)
+ builder (~> 3.0.0)
+ erubis (~> 2.7.0)
+ journey (~> 1.0.4)
+ rack (~> 1.4.5)
+ rack-cache (~> 1.2)
+ rack-test (~> 0.6.1)
+ sprockets (~> 2.2.1)
+ activemodel (3.2.14)
+ activesupport (= 3.2.14)
+ builder (~> 3.0.0)
+ activesupport (3.2.14)
+ i18n (~> 0.6, >= 0.6.4)
+ multi_json (~> 1.0)
+ addressable (2.3.5)
+ builder (3.0.4)
+ columnize (0.3.6)
+ debugger (1.6.3)
+ columnize (>= 0.3.1)
+ debugger-linecache (~> 1.2.0)
+ debugger-ruby_core_source (~> 1.2.4)
+ debugger-linecache (1.2.0)
+ debugger-ruby_core_source (1.2.4)
+ diff-lcs (1.2.5)
+ erubis (2.7.0)
+ faraday (0.8.8)
+ multipart-post (~> 1.2.0)
+ hashie (2.0.5)
+ hike (1.2.3)
+ i18n (0.6.4)
+ journey (1.0.4)
+ json (1.8.1)
+ multi_json (1.8.2)
+ multipart-post (1.2.0)
+ octokit (2.6.3)
+ sawyer (~> 0.5.1)
+ rack (1.4.5)
+ rack-cache (1.2)
+ rack (>= 0.4)
+ rack-ssl (1.3.3)
+ rack
+ rack-test (0.6.2)
+ rack (>= 1.0)
+ railties (3.2.14)
+ actionpack (= 3.2.14)
+ activesupport (= 3.2.14)
+ rack-ssl (~> 1.3.2)
+ rake (>= 0.8.7)
+ rdoc (~> 3.4)
+ thor (>= 0.14.6, < 2.0)
+ rake (10.1.0)
+ rdoc (3.12.2)
+ json (~> 1.4)
+ rspec-core (2.14.7)
+ rspec-expectations (2.14.4)
+ diff-lcs (>= 1.1.3, < 2.0)
+ rspec-mocks (2.14.4)
+ rspec-rails (2.14.0)
+ actionpack (>= 3.0)
+ activesupport (>= 3.0)
+ railties (>= 3.0)
+ rspec-core (~> 2.14.0)
+ rspec-expectations (~> 2.14.0)
+ rspec-mocks (~> 2.14.0)
+ sawyer (0.5.1)
+ addressable (~> 2.3.5)
+ faraday (~> 0.8, < 0.10)
+ sprockets (2.2.2)
+ hike (~> 1.2)
+ multi_json (~> 1.0)
+ rack (~> 1.0)
+ tilt (~> 1.1, != 1.3.0)
+ thor (0.18.1)
+ tilt (1.4.1)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ debugger
+ hashie
+ octokit
+ rspec-rails
diff --git a/plugins/github_relation/README.rdoc b/plugins/github_relation/README.rdoc
new file mode 100644
index 00000000000..0ce203c4127
--- /dev/null
+++ b/plugins/github_relation/README.rdoc
@@ -0,0 +1,3 @@
+= github_relation
+
+Description goes here
diff --git a/plugins/github_relation/app/controllers/github_project_controller.rb b/plugins/github_relation/app/controllers/github_project_controller.rb
new file mode 100644
index 00000000000..0f12ea31687
--- /dev/null
+++ b/plugins/github_relation/app/controllers/github_project_controller.rb
@@ -0,0 +1,57 @@
+class GithubProjectController < ApplicationController
+ unloadable
+
+ before_filter :find_project, :authorize
+
+ def index
+ if @github_project.present?
+ redirect_to :action => :show, id: @github_project.id, project_id: @project.id
+ else
+ redirect_to action: :new, project_id: @project.id
+ end
+ end
+
+ def show
+ end
+
+ def new
+ @github_project = GithubProject.new()
+ end
+
+ def edit
+ end
+
+ def create
+ @github_project = GithubProject.new(params[:github_project])
+ @github_project.project_id = @project.id
+
+ unless @github_project.save
+ render :action => :new
+ return
+ end
+ redirect_to :action => :show, id: @github_project.id, project_id: @project.id
+ end
+
+ def update
+ @github_project.attributes = params[:github_project]
+ @github_project.project_id = @project.id
+
+ unless @github_project.save
+ render :action => :edit
+ return
+ end
+ redirect_to :action => :show, id: @github_project.id, project_id: @project.id
+ end
+
+ def get_data
+ @github_project.get_from_github(params[:login], params[:password])
+ redirect_to :action => :show, id: @github_project.id, project_id: @project.id
+ end
+
+ private
+ def find_project
+ @project = Project.find(params[:project_id])
+ @github_project = GithubProject.where(project_id: @project.id).first
+ end
+
+end
diff --git a/plugins/github_relation/app/models/github_issue.rb b/plugins/github_relation/app/models/github_issue.rb
new file mode 100644
index 00000000000..6b9e90d70c4
--- /dev/null
+++ b/plugins/github_relation/app/models/github_issue.rb
@@ -0,0 +1,95 @@
+class GithubIssue < ActiveRecord::Base
+ attr_accessible :issue_number
+
+ has_many :github_issue_comments
+ has_many :relation_to, :class_name => 'GithubIssueRelation', :foreign_key => 'issue_from_id'
+
+ belongs_to :issue
+
+ def self.create_issues(project, list_issues)
+ created_data = list_issues.select do |issue_from_github|
+ github_issue = GithubIssue.where(issue_number: issue_from_github.number).first_or_create()
+ github_issue.update_from_github(project, issue_from_github)
+ end
+
+ GithubIssue.where(issue_number: created_data.map{|issue| issue.number})
+ end
+
+ def update_from_github(project, issue_from_github, status = :open)
+ self.build_issue if issue.nil?
+ return if issue.updated_on.present? && issue.updated_on > issue_from_github.updated_at
+
+ issue.subject = issue_from_github.title
+ issue.description = issue_from_github.body
+ issue.project = project
+ issue.tracker = Tracker.first
+ issue.author = GithubUser.user_by_github_login(issue_from_github.user)
+ if issue_from_github.assignee.present?
+ issue.assigned_to = GithubUser.user_by_github_login(issue_from_github.assignee)
+ end
+ issue.created_on = issue_from_github.created_at
+ issue.updated_on = issue_from_github.updated_at
+ case status
+ when :open
+ issue.closed_on = nil
+ issue.status = IssueStatus.where(is_closed: false).first
+ when :close
+ issue.closed_on = issue_from_github.closed_at
+ issue.status = IssueStatus.where(is_closed: true).first
+ else
+ end
+
+ Issue.skip_callback(:save, :before, :force_updated_on_change)
+ Issue.skip_callback(:save, :before, :update_closed_on)
+ issue.save!
+ Issue.set_callback(:save, :before, :force_updated_on_change)
+ Issue.set_callback(:save, :before, :update_closed_on)
+ self.save!
+ true
+ end
+
+ def self.closed_issues(list_issues)
+ github_issue_number = list_issues.map{|issue_from_github| issue_from_github.number}
+ GithubIssue.where(issue_id: self.project.issues.open.map{|issue| issue.id}).
+ where( GithubIssue.arel_table[:issue_number].not_in(github_issue_number))
+ end
+
+ def set_issue_comment_from_github(issue_comments)
+ issue_comments.each do |issue_comment_from_github|
+ issue_comment = github_issue_comments.where(issue_comment_number: issue_comment_from_github.id.to_s).first_or_create
+ issue_comment.github_issue = self
+ issue_comment.update_from_github(issue_comment_from_github)
+ issue_comment.save!
+ end
+
+ issue_comment_number = issue_comments.map {|issue_comment_from_github| issue_comment_from_github.id.to_s}
+ closed_issue_comments = github_issue_comments.where( GithubIssueComment.arel_table[:issue_comment_number].not_in(issue_comment_number))
+ closed_issue_comments.each do |issue_comment|
+ issue_comment.destroy
+ end
+ end
+
+ def create_and_delete_relation_issues
+ relation_to_issues.reject{|issue| relation_issues.any? {|relation| relation == issue}}.each do |issue|
+ relation_to.where(issue_to_id: issue.id).each do |to_issue|
+ to_issue.destroy
+ end
+ end
+
+ relation_issues.reject{|issue| relation_to_issues.any? {|relation| relation == issue}}.each do |issue|
+ relation_to.create issue_to_id: issue.id
+ end
+ end
+
+ private
+ def relation_issues
+ issue_numbers = github_issue_comments(true).inject([]) do |numbers, github_issue|
+ numbers + github_issue.relation_issues
+ end
+ GithubIssue.where(issue_number: issue_numbers.uniq)
+ end
+
+ def relation_to_issues
+ relation_to.map {|relation| relation.issue_to}
+ end
+end
diff --git a/plugins/github_relation/app/models/github_issue_comment.rb b/plugins/github_relation/app/models/github_issue_comment.rb
new file mode 100644
index 00000000000..66211743157
--- /dev/null
+++ b/plugins/github_relation/app/models/github_issue_comment.rb
@@ -0,0 +1,32 @@
+class GithubIssueComment < ActiveRecord::Base
+ attr_accessible :issue_comment_number
+
+ belongs_to :github_issue
+ belongs_to :journal
+
+ after_destroy :destroy_issue_comment
+
+ def update_from_github(issue_comment)
+ new_journal = self.journal || Journal.new(:journalized => github_issue.issue, :user => User.current)
+ new_journal.notes = issue_comment.body
+ new_journal.save!
+ self.journal = new_journal
+ end
+
+ def relation_issues
+ match_data = journal.notes.match /#(\d*)/
+
+ issue_ids = []
+ while match_data.present?
+ issue_ids << match_data[1].to_i
+ match_data = match_data.post_match.match /#(\d*)/
+ end
+
+ issue_ids
+ end
+
+ def destroy_issue_comment
+ self.journal.destroy
+ end
+
+end
diff --git a/plugins/github_relation/app/models/github_issue_relation.rb b/plugins/github_relation/app/models/github_issue_relation.rb
new file mode 100644
index 00000000000..01e8c1cc27c
--- /dev/null
+++ b/plugins/github_relation/app/models/github_issue_relation.rb
@@ -0,0 +1,24 @@
+class GithubIssueRelation < ActiveRecord::Base
+ attr_accessible :issue_from_id, :issue_to_id
+
+ belongs_to :issue_from, :class_name => 'GithubIssue', :foreign_key => 'issue_from_id'
+ belongs_to :issue_to, :class_name => 'GithubIssue', :foreign_key => 'issue_to_id'
+ belongs_to :issue_relation
+
+ after_create :create_issue_relation
+ after_destroy :destroy_issue_relation
+
+ private
+ def create_issue_relation
+ issue_relation = IssueRelation.new
+ issue_relation.issue_from = issue_from.issue
+ issue_relation.issue_to = issue_to.issue
+ issue_relation.save!
+ self.issue_relation = issue_relation
+ self.save!
+ end
+
+ def destroy_issue_relation
+ self.issue_relation.destroy
+ end
+end
diff --git a/plugins/github_relation/app/models/github_project.rb b/plugins/github_relation/app/models/github_project.rb
new file mode 100644
index 00000000000..8078d39a15c
--- /dev/null
+++ b/plugins/github_relation/app/models/github_project.rb
@@ -0,0 +1,28 @@
+class GithubProject < ActiveRecord::Base
+ attr_accessible :organization, :project_name
+
+ validates :organization, presence: true
+ validates :project_name, presence: true
+
+ belongs_to :project
+
+ def get_from_github(login, password)
+ github_relation = Github::Relation.new(login, password)
+
+ list_issues = github_relation.issues(self.organization, self.project_name)
+
+ updated_issues = GithubIssue.create_issues(self.project, list_issues)
+
+ closed_issues = GithubIssue.closed_issues(list_issues)
+ closed_issues.each do |issue|
+ github_issue = github_relation.issue(self.organization, self.project_name, issue.issue_number)
+ issue.update_from_github(self.project, github_issue, true)
+ end
+
+ (updated_issues + closed_issues).each do |issue|
+ issue_comments = github_relation.issue_comments(self.organization, self.project_name, issue.issue_number)
+ issue.set_issue_comment_from_github issue_comments
+ issue.create_and_delete_relation_issues
+ end
+ end
+end
diff --git a/plugins/github_relation/app/models/github_user.rb b/plugins/github_relation/app/models/github_user.rb
new file mode 100644
index 00000000000..fa008400fc1
--- /dev/null
+++ b/plugins/github_relation/app/models/github_user.rb
@@ -0,0 +1,33 @@
+class GithubUser < ActiveRecord::Base
+ attr_accessible :login
+
+ belongs_to :user
+
+ after_create :create_user
+
+ def self.create_users(users)
+ users.each do |user_from_github|
+ next if GithubUser.exists?(login: user_from_github.login)
+
+ GithubUser.create(login: user_from_github.login)
+ end
+ end
+
+ def self.user_by_github_login(user_by_github)
+ github_user = self.where(login: user_by_github.login).first_or_create
+ github_user.user
+ end
+
+ private
+ def create_user
+ return if User.exists?(login: self.login)
+
+ user = self.build_user
+ user.login = self.login
+ user.firstname = self.login
+ user.lastname = self.login
+ user.mail = "#{self.login}@piyo.hoge"
+ user.save!
+ self.save!
+ end
+end
diff --git a/plugins/github_relation/app/views/github_project/_form.html.erb b/plugins/github_relation/app/views/github_project/_form.html.erb
new file mode 100644
index 00000000000..0e32ab3144b
--- /dev/null
+++ b/plugins/github_relation/app/views/github_project/_form.html.erb
@@ -0,0 +1,12 @@
+<%= hidden_field_tag :project_id, @project.id %>
+
+
+ | <%= f.label :organization %> |
+ <%= f.text_field :organization %> |
+
+
+ | <%= f.label :project_name %> |
+ <%= f.text_field :project_name %> |
+
+
+<%= f.submit %>
\ No newline at end of file
diff --git a/plugins/github_relation/app/views/github_project/edit.html.erb b/plugins/github_relation/app/views/github_project/edit.html.erb
new file mode 100644
index 00000000000..1f51a2bfca8
--- /dev/null
+++ b/plugins/github_relation/app/views/github_project/edit.html.erb
@@ -0,0 +1,3 @@
+<%= form_for(@github_project,:url => {:action => :update} ) do |f| %>
+ <%= render 'form', f: f %>
+<% end %>
\ No newline at end of file
diff --git a/plugins/github_relation/app/views/github_project/index.html.erb b/plugins/github_relation/app/views/github_project/index.html.erb
new file mode 100644
index 00000000000..c9a970ec7af
--- /dev/null
+++ b/plugins/github_relation/app/views/github_project/index.html.erb
@@ -0,0 +1,15 @@
+GithubRelationController#index
+<%= form_tag(get_data_github_project_index_path, :method => :put) do %>
+ <%= hidden_field_tag :project_id, params[:project_id] %>
+
+
+ | <%= label_tag :login, 'login' %> |
+ <%= text_field_tag :login %> |
+
+
+ | <%= label_tag :password, 'password' %> |
+ <%= text_field_tag :password %> |
+
+
+ <%= submit_tag "get_data", {class: "btn"} %>
+<% end %>
\ No newline at end of file
diff --git a/plugins/github_relation/app/views/github_project/new.html.erb b/plugins/github_relation/app/views/github_project/new.html.erb
new file mode 100644
index 00000000000..cfb5a985953
--- /dev/null
+++ b/plugins/github_relation/app/views/github_project/new.html.erb
@@ -0,0 +1,3 @@
+<%= form_for(@github_project,:url => {:action => :create} ) do |f| %>
+ <%= render 'form', f: f %>
+<% end %>
\ No newline at end of file
diff --git a/plugins/github_relation/app/views/github_project/show.html.erb b/plugins/github_relation/app/views/github_project/show.html.erb
new file mode 100644
index 00000000000..eedf3752e44
--- /dev/null
+++ b/plugins/github_relation/app/views/github_project/show.html.erb
@@ -0,0 +1,31 @@
+
+
+ | organization |
+ <%= @github_project.organization %> |
+
+
+ | project_name |
+ <%= @github_project.project_name %> |
+
+
+<% if User.current.allowed_to?(:manage_github_relation, @project) %>
+ <%= link_to 'edit', edit_github_project_path(id:@github_project.id, project_id: @github_project.project.id), class: "icon icon-edit" %>
+<% end %>
+
+<% if User.current.allowed_to?(:get_from_github, @project) %>
+ <%= form_tag(get_data_github_project_index_path, method: :put) do %>
+ <%= hidden_field_tag :project_id, @project.id %>
+
+
+ | <%= label_tag :login %> |
+ <%= text_field_tag :login %> |
+
+
+ | <%= label_tag :password %> |
+ <%= text_field_tag :password %> |
+
+
+
+ <%= submit_tag 'get_from_github' %>
+ <% end %>
+<% end %>
\ No newline at end of file
diff --git a/plugins/github_relation/config/locales/en.yml b/plugins/github_relation/config/locales/en.yml
new file mode 100644
index 00000000000..642b07f8211
--- /dev/null
+++ b/plugins/github_relation/config/locales/en.yml
@@ -0,0 +1,3 @@
+# English strings go here for Rails i18n
+en:
+ # my_label: "My label"
diff --git a/plugins/github_relation/config/routes.rb b/plugins/github_relation/config/routes.rb
new file mode 100644
index 00000000000..7f0eb189e21
--- /dev/null
+++ b/plugins/github_relation/config/routes.rb
@@ -0,0 +1,9 @@
+# Plugin's routes
+# See: http://guides.rubyonrails.org/routing.html
+RedmineApp::Application.routes.draw do
+ resources :github_project do
+ collection do
+ put :get_data
+ end
+ end
+end
diff --git a/plugins/github_relation/db/migrate/001_create_github_issues.rb b/plugins/github_relation/db/migrate/001_create_github_issues.rb
new file mode 100644
index 00000000000..95c4a7b9d82
--- /dev/null
+++ b/plugins/github_relation/db/migrate/001_create_github_issues.rb
@@ -0,0 +1,8 @@
+class CreateGithubIssues < ActiveRecord::Migration
+ def change
+ create_table :github_issues do |t|
+ t.column :issue_number, :integer, :default => 0
+ t.references :issue
+ end
+ end
+end
diff --git a/plugins/github_relation/db/migrate/002_create_github_users.rb b/plugins/github_relation/db/migrate/002_create_github_users.rb
new file mode 100644
index 00000000000..b2333fbbbf9
--- /dev/null
+++ b/plugins/github_relation/db/migrate/002_create_github_users.rb
@@ -0,0 +1,8 @@
+class CreateGithubUsers < ActiveRecord::Migration
+ def change
+ create_table :github_users do |t|
+ t.column :login, :string
+ t.references :user
+ end
+ end
+end
diff --git a/plugins/github_relation/db/migrate/003_create_github_projects.rb b/plugins/github_relation/db/migrate/003_create_github_projects.rb
new file mode 100644
index 00000000000..9011e5908a2
--- /dev/null
+++ b/plugins/github_relation/db/migrate/003_create_github_projects.rb
@@ -0,0 +1,9 @@
+class CreateGithubProjects < ActiveRecord::Migration
+ def change
+ create_table :github_projects do |t|
+ t.column :organization, :string
+ t.column :project_name, :string
+ t.references :project
+ end
+ end
+end
\ No newline at end of file
diff --git a/plugins/github_relation/db/migrate/004_create_github_issue_comments.rb b/plugins/github_relation/db/migrate/004_create_github_issue_comments.rb
new file mode 100644
index 00000000000..50b61923c74
--- /dev/null
+++ b/plugins/github_relation/db/migrate/004_create_github_issue_comments.rb
@@ -0,0 +1,9 @@
+class CreateGithubIssueComments < ActiveRecord::Migration
+ def change
+ create_table :github_issue_comments do |t|
+ t.column :issue_comment_number, :string
+ t.references :github_issue
+ t.references :journal
+ end
+ end
+end
\ No newline at end of file
diff --git a/plugins/github_relation/db/migrate/005_create_github_issue_relations.rb b/plugins/github_relation/db/migrate/005_create_github_issue_relations.rb
new file mode 100644
index 00000000000..1129420385e
--- /dev/null
+++ b/plugins/github_relation/db/migrate/005_create_github_issue_relations.rb
@@ -0,0 +1,9 @@
+class CreateGithubIssueRelations < ActiveRecord::Migration
+ def change
+ create_table :github_issue_relations do |t|
+ t.references :issue_relation
+ t.references :issue_from
+ t.references :issue_to
+ end
+ end
+end
\ No newline at end of file
diff --git a/plugins/github_relation/init.rb b/plugins/github_relation/init.rb
new file mode 100644
index 00000000000..27066120dc6
--- /dev/null
+++ b/plugins/github_relation/init.rb
@@ -0,0 +1,15 @@
+Redmine::Plugin.register :github_relation do
+ name 'Github Relation plugin'
+ author 'Author name'
+ description 'This is a plugin for Redmine'
+ version '0.0.1'
+ url 'http://example.com/path/to/plugin'
+ author_url 'http://example.com/about'
+
+ project_module :github_project do
+ permission :manage_github_relation, :github_project => [:new, :edit, :create, :update]
+ permission :show_github_relation, :github_project => [:index, :show]
+ permission :get_from_github, :github_project => [:get_data]
+ end
+ menu :project_menu, :github_project, {controller: :github_project, action: :index}, :caption => 'github_relation', :after => :activity, :param => :project_id
+end
diff --git a/plugins/github_relation/lib/github/relation.rb b/plugins/github_relation/lib/github/relation.rb
new file mode 100644
index 00000000000..01d56b9ef44
--- /dev/null
+++ b/plugins/github_relation/lib/github/relation.rb
@@ -0,0 +1,49 @@
+module Github
+ class Relation
+
+ def initialize(login, password)
+ @login = login
+ @password = password
+ end
+
+ def client
+ @client || Octokit::Client.new(login: @login, password: @password)
+ end
+
+ def issues(organization, project)
+ all_list_from_github(organization, project) do |repo, option|
+ client.list_issues(repo, option)
+ end
+ end
+
+ def issue_comments(organization, project, number)
+ all_list_from_github(organization, project) do |repo, option|
+ client.issue_comments(repo, number, option)
+ end
+ end
+
+ def issue(organization, project, number)
+ target = "#{organization}/#{project}"
+ client.issue(target, number)
+ end
+
+ def users(organization)
+ client.organization_members(organization)
+ rescue
+ []
+ end
+
+ private
+ def all_list_from_github(organization, project)
+ repo = "#{organization}/#{project}"
+
+ list_all = []
+ begin
+ page = (page || 0) + 1
+ list = yield repo, {page: page, per_page: 100}
+ list_all += list
+ end
+ list_all
+ end
+ end
+end
\ No newline at end of file
diff --git a/plugins/github_relation/spec/models/github_issue_spec.rb b/plugins/github_relation/spec/models/github_issue_spec.rb
new file mode 100644
index 00000000000..8ede0527f92
--- /dev/null
+++ b/plugins/github_relation/spec/models/github_issue_spec.rb
@@ -0,0 +1,178 @@
+require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+
+describe 'github_issue' do
+ fixtures :trackers, :issue_statuses, :enumerations, :users
+
+ let!(:project){Project.create(name: 'github_test', identifier: 'github_test')}
+
+ let!(:github_users){
+ %w{user assignee}.map do |user_name|
+ user = Hashie::Mash.new
+ user.login = "#{user_name}_login"
+ user
+ end
+ }
+
+ before do
+ github_issues = 10.times.map do |index|
+ issue = Hashie::Mash.new
+ issue.number = index
+ issue.title = "title#{index}"
+ issue.body = "body#{index}"
+ issue.created_at = Time.parse("2010/01/01")
+ issue.updated_at = Time.parse("2011/01/01")
+ issue.user = github_users[0]
+ issue
+ end
+ github_issues[5].assignee = github_users[1]
+ github_issues[6].user.login = "hoge"
+
+ GithubIssue.create_issues(project, github_issues)
+ end
+
+ context "create_issues" do
+ subject{GithubIssue.scoped.order(:issue_number)}
+ its(:count){should == 10}
+ it "GithubIssues" do
+ subject.each_with_index do |github_issue, index|
+ github_issue.issue_number.should == index
+ github_issue.issue.subject.should == "title#{index}"
+ github_issue.issue.description.should == "body#{index}"
+ github_issue.issue.created_on.should == Time.parse("2010/01/01")
+ github_issue.issue.updated_on.should == Time.parse("2011/01/01")
+ end
+ end
+ it "GithubIssues User" do
+ user = GithubUser.where(login: "user_login").first.user
+
+ (0..4).each do |index|
+ subject[index].issue.author.should == user
+ subject[index].issue.assigned_to.should == nil
+ end
+ (7..9).each do |index|
+ subject[index].issue.author.should == user
+ subject[index].issue.assigned_to.should == nil
+ end
+
+ subject[5].issue.author.should == user
+ subject[5].issue.assigned_to.should == GithubUser.where(login: "assignee_login").first.user
+ subject[6].issue.author.should == GithubUser.where(login: "hoge").first.user
+ subject[6].issue.assigned_to.should == nil
+ end
+ end
+
+ context "update_closed_issues" do
+ before do
+ issue = Hashie::Mash.new
+ issue.number = 3
+ issue.title = "title3"
+ issue.body = "body3"
+ issue.created_at = Time.parse("2010/01/01")
+ issue.updated_at = Time.parse("2011/01/01")
+ issue.closed_at = Time.parse("2012/01/01")
+ issue.user = github_users[0]
+
+ github_issue = GithubIssue.where(issue_number: 3).first
+ github_issue.update_from_github(project, issue, :close)
+ end
+
+ subject{GithubIssue.scoped.order(:issue_number)}
+
+ it "GithubIssues closed_on" do
+ subject.each_with_index do |github_issue, index|
+ unless index == 3
+ github_issue.issue.closed_on.present?.should == false
+ github_issue.issue.status.is_closed?.should == false
+ end
+ end
+ subject[3].issue.closed_on.should == Time.parse("2012/01/01")
+ subject[3].issue.status.is_closed?.should == true
+ end
+
+ end
+
+ describe "issue_comments" do
+ let!(:issue){GithubIssue.first}
+ before do
+ issue_comments = 10.times.map do |index|
+ comment = Hashie::Mash.new
+ comment.id = index
+ comment.body = "body#{index} ##{index + 1} ##{index + 2}"
+ comment
+ end
+
+ issue.set_issue_comment_from_github(issue_comments)
+ issue.create_and_delete_relation_issues
+ end
+
+ subject{GithubIssueComment.scoped.order(:id)}
+
+ context "create_from_github" do
+ its(:count){should == 10}
+ it "github_comment" do
+ subject.each_with_index do |issue_comment, index|
+ issue_comment.issue_comment_number.should == index.to_s
+ issue_comment.github_issue.should == issue
+ issue_comment.journal.notes.should == "body#{index} ##{index + 1} ##{index + 2}"
+ end
+ end
+
+ it "github_relation" do
+ issue_relations = IssueRelation.all
+ issue_relations.count.should == 9
+
+ issue_relations.each_with_index do |issue_relation, index|
+ issue_relation.issue_from.should == issue.issue
+ issue_relation.issue_to.should == GithubIssue.where(issue_number: (index + 1).to_s).first.issue
+ end
+ end
+ end
+
+ context "update_and_delete_from_github" do
+ before do
+ issue_comments = 4.times.map do |index|
+ comment = Hashie::Mash.new
+ comment.id = index
+ comment.body = "body#{index + 1}"
+ comment
+ end
+ issue_comments += 4.times.map do |index|
+ comment = Hashie::Mash.new
+ comment.id = index + 4
+ comment.body = "body#{index + 5} ##{index + 6} ##{index + 7}"
+ comment
+ end
+
+ issue.set_issue_comment_from_github(issue_comments)
+ issue.create_and_delete_relation_issues
+ end
+
+ its(:count){should == 8}
+ it "github_comment" do
+ (0..3).each do |index|
+ issue_comment = subject[index]
+ issue_comment.issue_comment_number.should == index.to_s
+ issue_comment.github_issue.should == issue
+ issue_comment.journal.notes.should == "body#{index + 1}"
+ end
+ (4..7).each do |index|
+ issue_comment = subject[index]
+ issue_comment.issue_comment_number.should == index.to_s
+ issue_comment.github_issue.should == issue
+ issue_comment.journal.notes.should == "body#{index + 1} ##{index + 2} ##{index + 3}"
+ end
+
+ end
+
+ it "github_relation" do
+ issue_relations = IssueRelation.all
+ issue_relations.count.should == 4
+
+ issue_relations.each_with_index do |issue_relation, index|
+ issue_relation.issue_from.should == issue.issue
+ issue_relation.issue_to.should == GithubIssue.where(issue_number: (index + 6).to_s).first.issue
+ end
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/plugins/github_relation/spec/models/github_user_spec.rb b/plugins/github_relation/spec/models/github_user_spec.rb
new file mode 100644
index 00000000000..3041a64bed6
--- /dev/null
+++ b/plugins/github_relation/spec/models/github_user_spec.rb
@@ -0,0 +1,61 @@
+require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+
+describe 'github_user' do
+ let!(:project){Project.create(name: 'github_test', identifier: 'github_test')}
+
+ describe "create_users" do
+ before do
+ github_users =
+ 10.times.map do |index|
+ user = Hashie::Mash.new
+ user.login = "login#{index}"
+ user
+ end
+ GithubUser.create_users(github_users)
+ end
+
+ context "create" do
+ subject{GithubUser.scoped.order(:login)}
+ its(:count){should == 10}
+ it "GithubUsers" do
+ subject.each_with_index do |github_user, index|
+ github_user.login.should == "login#{index}"
+ end
+ end
+ end
+
+ context "duplicate" do
+ before do
+ user = Hashie::Mash.new
+ user.login = "login6"
+ GithubUser.create_users([user])
+ end
+
+ subject{GithubUser.scoped.order(:login)}
+ its(:count){should == 10}
+ it "GithubUsers" do
+ subject.each_with_index do |github_user, index|
+ github_user.login.should == "login#{index}"
+ end
+ end
+ end
+
+ context "add" do
+ before do
+ user = Hashie::Mash.new
+ user.login = "login10"
+ GithubUser.create_users([user])
+ end
+
+ subject{GithubUser.scoped.order(:login)}
+ its(:count){should == 11}
+ it "GithubUsers" do
+ login_idx = [0,1,10,2,3,4,5,6,7,8,9]
+
+ subject.each_with_index do |github_user, index|
+ github_user.login.should == "login#{login_idx[index]}"
+ end
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/plugins/github_relation/spec/spec_helper.rb b/plugins/github_relation/spec/spec_helper.rb
new file mode 100644
index 00000000000..e8387235334
--- /dev/null
+++ b/plugins/github_relation/spec/spec_helper.rb
@@ -0,0 +1,39 @@
+# This file is copied to spec/ when you run 'rails generate rspec:install'
+ENV["RAILS_ENV"] ||= 'test'
+require File.expand_path("../../../../config/environment", __FILE__)
+require 'rspec/rails'
+require 'rspec/autorun'
+require 'hashie'
+
+# Requires supporting ruby files with custom matchers and macros, etc,
+# in spec/support/ and its subdirectories.
+Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
+
+RSpec.configure do |config|
+ # ## Mock Framework
+ #
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
+ #
+ # config.mock_with :mocha
+ # config.mock_with :flexmock
+ # config.mock_with :rr
+
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
+ config.fixture_path = "#{::Rails.root}/test/fixtures"
+
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
+ # examples within a transaction, remove the following line or assign false
+ # instead of true.
+ config.use_transactional_fixtures = true
+
+ # If true, the base class of anonymous controllers will be inferred
+ # automatically. This will be the default behavior in future versions of
+ # rspec-rails.
+ config.infer_base_class_for_anonymous_controllers = false
+
+ # Run specs in random order to surface order dependencies. If you find an
+ # order dependency and want to debug it, you can fix the order by providing
+ # the seed, which is printed after each run.
+ # --seed 1234
+ config.order = "random"
+end
diff --git a/plugins/github_relation/test/functional/github_relation_controller_test.rb b/plugins/github_relation/test/functional/github_relation_controller_test.rb
new file mode 100644
index 00000000000..474001e1726
--- /dev/null
+++ b/plugins/github_relation/test/functional/github_relation_controller_test.rb
@@ -0,0 +1,8 @@
+require File.expand_path('../../test_helper', __FILE__)
+
+class GithubRelationControllerTest < ActionController::TestCase
+ # Replace this with your real tests.
+ def test_truth
+ assert true
+ end
+end
diff --git a/plugins/github_relation/test/functional/index_controller_test.rb b/plugins/github_relation/test/functional/index_controller_test.rb
new file mode 100644
index 00000000000..606b4c89b90
--- /dev/null
+++ b/plugins/github_relation/test/functional/index_controller_test.rb
@@ -0,0 +1,8 @@
+require File.expand_path('../../test_helper', __FILE__)
+
+class IndexControllerTest < ActionController::TestCase
+ # Replace this with your real tests.
+ def test_truth
+ assert true
+ end
+end
diff --git a/plugins/github_relation/test/test_helper.rb b/plugins/github_relation/test/test_helper.rb
new file mode 100644
index 00000000000..54685d33ca5
--- /dev/null
+++ b/plugins/github_relation/test/test_helper.rb
@@ -0,0 +1,2 @@
+# Load the Redmine helper
+require File.expand_path(File.dirname(__FILE__) + '/../../../test/test_helper')