Created
November 15, 2012 16:22
-
-
Save jakimowicz/4079496 to your computer and use it in GitHub Desktop.
Revisions
-
jakimowicz created this gist
Nov 15, 2012 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,341 @@ #!/usr/bin/env ruby require 'faraday' require 'json' require 'gitlab' module Redmine Host = nil APIKey = nil def self.connection raise 'must define a Host' if Host.nil? @connection ||= Faraday.new(:url => Host) do |faraday| # faraday.response :logger faraday.adapter Faraday.default_adapter end end def self.get(path, attrs = {}) raise 'must define an APIKey' if APIKey.nil? result = connection.get(path, attrs) do |req| req.headers['X-Redmine-API-Key'] = APIKey end JSON.parse result.body end def self.post(path, attrs = {}, body = nil) raise 'must define an APIKey' if APIKey.nil? result = connection.post(path, attrs) do |req| req.body = body req.headers['Content-Type'] = 'application/json' req.headers['X-Redmine-API-Key'] = APIKey end JSON.parse result.body end def self.put(path, attrs = {}, body = nil) raise 'must define an APIKey' if APIKey.nil? result = connection.put(path, attrs) do |req| req.body = body req.headers['Content-Type'] = 'application/json' req.headers['X-Redmine-API-Key'] = APIKey end end class Base attr_accessor :id, :attributes def self.pluralized_resource_name @pluralized_resource_name ||= "#{self.resource_name}s" end def self.resource_name @resource_name ||= self.name.split('::').last.downcase end def self.list(options = {}) list = Redmine.get "#{pluralized_resource_name}.json", options raise "did not find any #{pluralized_resource_name} in #{list.inspect}" if list[pluralized_resource_name].nil? list[pluralized_resource_name].collect do |attributes| obj = new obj.attributes = attributes obj end end def self.find(id) @find ||= {} return @find[id] if @find[id] response = Redmine.get "#{pluralized_resource_name}/#{id}.json" obj = new obj.attributes = response[resource_name] @find[id] = obj end def method_missing(sym) self.attributes[sym.to_s] end def id self.attributes['id'] end end class Project < Base def issues(options = {}) @issues ||= Issue.list(options.merge(:status_id => '*', :project_id => self.id, :limit => 999)) end def categories @categories ||= IssueCategory.list :project_id => self.id end def category_by_name(name) @category_by_name ||= {} @category_by_name[name] ||= categories.detect { |category| category.name == name } end def self.by_identifier(identifier) self.list.detect { |project| project.identifier == identifier } end end class User < Base def self.by_email(email) @by_email ||= {} @by_email[email] ||= self.list.detect { |user| user.mail == email } end end class Issue < Base def self.create(project, subject, description, attributes = {}) body = { :issue => { :project_id => project.id, :subject => subject, :description => description, :tracker_id => Tracker.first.id, :priority_id => 4 }.merge(attributes) }.to_json response = Redmine.post 'issues.json', {}, body end def update(new_attributes = {}) changes = {} new_attributes.each do |key, value| if key.match(/_id$/) if self.attributes[key.to_s.gsub(/_id$/, '')] and self.attributes[key.to_s.gsub(/_id$/, '')]['id'].to_s != value.to_s changes[key] = value end else changes[key] = value if self.attributes[key.to_s].to_s != value.to_s end end if changes.empty? puts 'no changes !' return end puts "changes: #{changes.inspect}" response = Redmine.put "issues/#{self.id}.json", {}, { :issue => changes }.to_json end def author Redmine::User.find self.attributes['author']['id'] end def assignee Redmine::User.find self.attributes['assigned_to']['id'] rescue nil end end class IssueStatus < Base def self.pluralized_resource_name ; 'issue_statuses' ; end def self.resource_name ; 'issue_status' ; end def self.by_name(name) @by_name ||= {} @by_name[name] ||= list.detect { |status| status.name == name } end end class IssueCategory < Base def self.pluralized_resource_name ; 'issue_categories' ; end def self.resource_name ; 'issue_category' ; end def self.list(options = {}) raise "must provide a project_id" if options[:project_id].nil? list = Redmine.get "projects/#{options.delete :project_id}/issue_categories.json", options raise "did not find any issue_categories in #{list.inspect}" if list['issue_categories'].nil? list['issue_categories'].collect do |attributes| obj = new obj.attributes = attributes obj end end end class Tracker < Base def self.first @first ||= self.list.first end end end Redmine::Host = '' Redmine::APIKey = '' Gitlab.configure do |config| config.endpoint = '' config.private_token = '' end # puts Redmine::IssueStatus.list.inspect # puts Redmine::IssueStatus.by_name('Assigned').inspect # puts Redmine::Project.list.first.categories.inspect # puts Redmine::Project.list.first.category_by_name('gitlab bug').inspect # puts Redmine::Issue.create(Redmine::Project.list.first, 'testing creation from script', 'bleh', :assigned_to_id => 3, :status_id => Redmine::IssueStatus.by_name('Assigned').id, :category_id => Redmine::Project.list.first.category_by_name('gitlab task').id) Gitlab.projects.each do |gitlab_project| puts "iterating over project #{gitlab_project.name}" # First, find a project matching the gitlab one redmine_project = Redmine::Project.by_identifier(gitlab_project.name) next if redmine_project.nil? redmine_issues = redmine_project.issues gitlab_issues = Gitlab.issues(gitlab_project.id) processed_gitlab_issues = [] puts "found #{gitlab_issues.count} issues on gitlab" # Then, iterate through all redmine issues of the project redmine_issues.each do |redmine_issue| puts "processing redmine issue #{redmine_issue.id} #{redmine_issue.subject}" # Skipping non gitlab issues next if redmine_issue.category.nil? or redmine_issue.category['name'].match(/^gitlab/).nil? # Find corresponding assignee in gitlab gitlab_assignee = Gitlab.users.detect { |u| u.email == redmine_issue.assignee.mail } unless redmine_issue.assignee.nil? gitlab_assignee_id = gitlab_assignee ? gitlab_assignee.id : nil puts "gitlab assignee: #{gitlab_assignee.inspect}" # Search for an existing issue existing_issue = gitlab_issues.detect { |gitlab_issue| gitlab_issue.title == redmine_issue.subject} puts "issue already existing on gitlab" if existing_issue if existing_issue # Existing issue, updating status if Time.parse(existing_issue.updated_at) < Time.parse(redmine_issue.updated_on) puts "gitlab issue is older than redmine, updating gitlab issue" processed_gitlab_issues << existing_issue unless existing_issue.nil? Gitlab.edit_issue gitlab_project.id, existing_issue.id, :title => redmine_issue.subject, :description => redmine_issue.description, :assignee_id => gitlab_assignee_id, :labels => redmine_issue.category['name'].gsub(/gitlab/, '').strip, :closed => redmine_issue.status['name'] == 'Closed' else puts "gitlab issue is newer than redmine, skip the update" end else # No existing issue, creating it puts "creating issue on gitlab" created_issue = Gitlab.create_issue gitlab_project.id, redmine_issue.subject, :description => redmine_issue.description, :assignee_id => gitlab_assignee_id, :labels => redmine_issue.category['name'].gsub(/gitlab/, '').strip processed_gitlab_issues << existing_issue unless existing_issue.nil? end end (gitlab_issues - processed_gitlab_issues).each do |gitlab_issue| puts "processing gitlab issue #{gitlab_issue.id} #{gitlab_issue.title}" # Find corresponding assignee in redmine redmine_assignee = Redmine::User.by_email(gitlab_issue.assignee.email) unless gitlab_issue.assignee.nil? redmine_assignee_id = redmine_assignee ? redmine_assignee.id : nil # Search for an existing issue existing_issue = redmine_issues.detect { |redmine_issue| gitlab_issue.title == redmine_issue.subject } puts "issue already existing on redmine" if existing_issue status = case when gitlab_issue.closed 'Closed' when gitlab_issue.assignee 'Assigned' else 'New' end status_id = Redmine::IssueStatus.by_name(status).id if existing_issue # Existing issue, updating status puts "updatig issue on redmine" existing_issue.update :description => gitlab_issue.description, :assigned_to_id => redmine_assignee_id, :status_id => status_id, :done_ratio => gitlab_issue.closed ? '100' : '0' else # No existing issue, creating it puts "creating issue on redmine" Redmine::Issue.create( redmine_project, gitlab_issue.title, gitlab_issue.description, :assigned_to_id => redmine_assignee_id, :status_id => status_id, :category_id => Redmine::Project.list.first.category_by_name("gitlab").id, :done_ratio => gitlab_issue.closed ? '100' : '0' ) end end end # puts Redmine::Issue.list.first.inspect # puts Redmine::User.find(3).inspect # puts Redmine::User.find(3).mail # puts Gitlab.users.detect { |u| u.email == Redmine::User.find(3).mail }.inspect # puts Gitlab.users.collect &:email # puts Redmine::Issue.list.first.author.inspect # puts Gitlab.projects.inspect # puts Gitlab.issues.first.title # puts Redmine::Project.list.first.id.inspect # puts Redmine::Issue.list(:limit => 500).count # # puts '===' # puts '===' # puts '===' # # puts Redmine::Project.list.first.issues.inspect # puts Redmine::Issue.find(778).inspect # puts Redmine::Project.by_identifier('bureau-dr').inspect