bpescatore-stash 0.3.2

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.
@@ -0,0 +1,153 @@
1
+ require 'json'
2
+ require 'net/https'
3
+ require 'uri'
4
+ require 'git'
5
+ require 'launchy'
6
+
7
+ include Atlassian::Util::TextUtil
8
+
9
+ module Atlassian
10
+ module Stash
11
+ class CreatePullRequestResource
12
+ attr_accessor :resource
13
+
14
+ def initialize(sourceRepoInfo, targetRepoInfo, title, description, reviewers, source, target)
15
+ src_repository = {
16
+ 'slug' => sourceRepoInfo.slug,
17
+ 'project' => {
18
+ 'key' => sourceRepoInfo.projectKey
19
+ }
20
+ }
21
+ target_repository = {
22
+ 'slug' => targetRepoInfo.slug,
23
+ 'project' => {
24
+ 'key' => targetRepoInfo.projectKey
25
+ }
26
+ }
27
+ fromRef = {
28
+ 'id' => source,
29
+ 'repository' => src_repository
30
+ }
31
+ toRef = {
32
+ 'id' => target,
33
+ 'repository' => target_repository
34
+ }
35
+ @resource = {
36
+ 'title' => title,
37
+ 'fromRef' => fromRef,
38
+ 'toRef' => toRef
39
+ }
40
+
41
+ @resource["description"] = description unless description.empty?
42
+
43
+ @resource["reviewers"] = reviewers.collect { |r|
44
+ {
45
+ 'user' => {
46
+ 'name' => r
47
+ }
48
+ }
49
+ } unless reviewers.empty?
50
+ end
51
+ end
52
+
53
+ class CreatePullRequest
54
+
55
+ def initialize(config)
56
+ @config = config
57
+ end
58
+
59
+ def create_pull_request(source, target, reviewers, options)
60
+ Process.exit if not target or not source
61
+
62
+ @source = source
63
+ @target = target
64
+
65
+ srcRepoInfo = RepoInfo.create(@config, options.src_remote)
66
+ targetRepoInfo = RepoInfo.create(@config, options.target_remote)
67
+
68
+ title, description = title_and_description(options)
69
+
70
+ resource = CreatePullRequestResource.new(srcRepoInfo, targetRepoInfo, title, description, reviewers, @source, @target).resource
71
+
72
+ username = @config["username"]
73
+ password = @config["password"]
74
+ proxy_addr, proxy_port = parse_proxy(@config["proxy"])
75
+
76
+ username = ask("Username: ") unless @config["username"]
77
+ password = ask("Password: ") { |q| q.echo = '*' } unless @config["password"]
78
+
79
+ uri = URI.parse(@config["stash_url"])
80
+ prPath = targetRepoInfo.repoPath + '/pull-requests'
81
+
82
+ req = Net::HTTP::Post.new(uri.query.nil? ? "#{prPath}" : "#{prPath}?#{uri.query}", {'Content-Type' => 'application/json', 'Accept' => 'application/json'})
83
+ req.basic_auth username, password
84
+ req.body = resource.to_json
85
+ http = Net::HTTP.new(uri.host, uri.port, proxy_addr, proxy_port)
86
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @config["ssl_no_verify"]
87
+ http.use_ssl = uri.scheme.eql?("https")
88
+
89
+ response = http.start {|conn| conn.request(req) }
90
+
91
+ if not response.is_a? Net::HTTPCreated
92
+ responseBody = JSON.parse(response.body)
93
+ if responseBody['errors']
94
+ responseBody['errors'].collect { |error|
95
+ puts error['message']
96
+ if error['reviewerErrors']
97
+ error['reviewerErrors'].collect { |revError|
98
+ puts revError['message']
99
+ }
100
+ end
101
+ }
102
+ elsif responseBody['message']
103
+ puts responseBody['message']
104
+ else
105
+ puts 'An unknown error occurred.'
106
+ puts response.code
107
+ puts response.body
108
+ end
109
+ else
110
+ responseBody = JSON.parse(response.body)
111
+ prUri = uri.clone
112
+ prUri.path = prPath + '/' + responseBody['id'].to_s
113
+ prUri.query = uri.query
114
+ puts prUri.to_s
115
+
116
+ if @config["open"] || options.open
117
+ Launchy.open prUri.to_s
118
+ end
119
+ end
120
+ end
121
+
122
+ private
123
+
124
+ def title_from_branch
125
+ convert_branch_name_to_sentence(@source) || "Merge '#{@source}' into '#{@target}'"
126
+ end
127
+
128
+ def git_commit_messages
129
+ @commit_messages ||= `git log --reverse --format=%s #{@target}..#{@source}`
130
+ end
131
+
132
+ def parse_proxy(conf)
133
+ return nil, nil unless conf
134
+
135
+ addr, port = conf.split(":")
136
+ if port =~ /\d+/
137
+ port = port.to_i
138
+ else
139
+ port = nil
140
+ end
141
+ [addr, port]
142
+ end
143
+
144
+ def title_and_description(options)
145
+ descr = (options.description or git_commit_messages)
146
+ title = (options.title or title_from_branch)
147
+
148
+ [title, descr]
149
+ end
150
+ end
151
+ end
152
+ end
153
+
@@ -0,0 +1,62 @@
1
+ require 'git'
2
+
3
+ module Atlassian
4
+ module Stash
5
+ class RepoInfo
6
+ def initialize(config, projectKey, slug)
7
+ @config = config
8
+ @projectKey = projectKey
9
+ @slug = slug
10
+ end
11
+
12
+ def projectKey
13
+ @projectKey
14
+ end
15
+
16
+ def slug
17
+ @slug
18
+ end
19
+
20
+ def repoPath
21
+ uri = URI.parse(@config["stash_url"])
22
+ repoPath = uri.path + '/projects/' + @projectKey + '/repos/' + @slug
23
+ repoPath
24
+ end
25
+
26
+ def repoUrl(suffix, branch)
27
+ uri = URI.parse(@config["stash_url"])
28
+ path = repoPath + (suffix.nil? ? '' : '/' + suffix)
29
+ uri.path = path
30
+
31
+ if (!branch.nil? and !branch.empty?)
32
+ q = uri.query || ''
33
+ q = q + (q.empty? ? '' : '&') + 'at=' + branch unless branch.nil?
34
+ uri.query = q
35
+ end
36
+
37
+ uri.to_s
38
+ end
39
+
40
+ def self.create (config, remote=nil)
41
+ config = Hash.new if config.nil?
42
+ remote = config["remote"] if (remote.nil? || remote.empty?)
43
+ remoteUrl = Atlassian::Stash::Git.get_remote_url(remote)
44
+
45
+ if remoteUrl.nil?
46
+ remotes = Atlassian::Stash::Git.get_remotes
47
+ if remotes.empty?
48
+ raise "No git remotes found, could not determine Stash project URL"
49
+ else
50
+ remote = Atlassian::Stash::Git::DEFAULT_REMOTE if (remote.nil? || remote.empty?)
51
+ raise "Could not find requested git remote '#{remote}'. Remotes found: \r\n" + remotes
52
+ end
53
+ end
54
+
55
+ if m = remoteUrl.match(/\/([a-zA-Z~][a-zA-Z0-9_\-]*)\/([[:alnum:]][\w\-\.]*).git$/)
56
+ return RepoInfo.new(config, m[1], m[2])
57
+ end
58
+ raise "Repository does not seem to be hosted in Stash; Remote url: " + remoteUrl
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,9 @@
1
+
2
+ module Atlassian
3
+ module Stash
4
+ module Version
5
+ STRING = IO.readlines(File.dirname(__FILE__) + "/../../../VERSION").first.strip
6
+ end
7
+ end
8
+ end
9
+
@@ -0,0 +1,31 @@
1
+
2
+ module Atlassian
3
+ module Util
4
+ module TextUtil
5
+ def convert_branch_name_to_sentence(branch_name)
6
+ return '' if branch_name.nil?
7
+
8
+ branch_name = branch_name.to_s
9
+ return '' if branch_name.empty?
10
+
11
+ issue_key_regex = /([A-Z]{1,10}-\d+)/
12
+ branch_components = branch_name.split(issue_key_regex);
13
+
14
+ parts = branch_components.each_with_index.map { |value, index|
15
+ (index % 2 === 0) ? value.gsub(/[\-_]/, ' ') : value
16
+ }
17
+
18
+ to_sentence_case(parts.join(''))
19
+ end
20
+
21
+ def to_sentence_case(str)
22
+ return '' if str.nil?
23
+
24
+ str = str.to_s
25
+ return '' if str.empty?
26
+
27
+ str.slice(0, 1).upcase + str.slice(1, str.length)
28
+ end
29
+ end
30
+ end
31
+ end
data/lib/stash_cli.rb ADDED
@@ -0,0 +1,3 @@
1
+
2
+ Dir[File.join(File.dirname(__FILE__), "atlassian", "util", "*.rb")].sort.each {|f| require f}
3
+ Dir[File.join(File.dirname(__FILE__), "atlassian", "stash", "*.rb")].sort.each {|f| require f}
data/test/helper.rb ADDED
@@ -0,0 +1,29 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ if ENV["COVERAGE"]
5
+ require "simplecov"
6
+ SimpleCov.start :test_frameworks do
7
+ add_filter "/vendor/"
8
+ end
9
+ end
10
+
11
+ begin
12
+ Bundler.setup(:default, :development)
13
+ rescue Bundler::BundlerError => e
14
+ $stderr.puts e.message
15
+ $stderr.puts "Run `bundle install` to install missing gems"
16
+ exit e.status_code
17
+ end
18
+ require 'minitest/autorun'
19
+ require 'shoulda'
20
+ require "mocha/mini_test"
21
+
22
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
23
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
24
+ # require 'atlassian-stash'
25
+ require File.dirname(__FILE__) + "/../lib/stash_cli"
26
+
27
+
28
+ class Minitest::Test
29
+ end
@@ -0,0 +1,84 @@
1
+ require 'helper'
2
+
3
+ include Atlassian::Stash
4
+ include Atlassian::Stash::Git
5
+
6
+ class TestStashCreatePullRequest < Minitest::Test
7
+
8
+ context "#parse_proxy" do
9
+ setup do
10
+ @cpr = CreatePullRequest.new nil
11
+ end
12
+
13
+ context 'when proxy_conf is nil' do
14
+ should 'returns [nil, nil]' do
15
+ assert_equal [nil, nil], @cpr.send(:parse_proxy, nil)
16
+ end
17
+ end
18
+
19
+ context 'when proxy_conf is blank' do
20
+ should 'returns [nil, nil]' do
21
+ assert_equal [nil, nil], @cpr.send(:parse_proxy, "")
22
+ end
23
+ end
24
+
25
+ context 'when proxy_conf is "proxy.example.com"' do
26
+ should 'returns ["proxy.example.com", nil]' do
27
+ assert_equal ["proxy.example.com", nil], @cpr.send(:parse_proxy, "proxy.example.com")
28
+ end
29
+ end
30
+
31
+ context 'when proxy_conf is "proxy.example.com:8080"' do
32
+ should 'returns ["proxy.example.com", 8080]' do
33
+ assert_equal ["proxy.example.com", 8080], @cpr.send(:parse_proxy, "proxy.example.com:8080")
34
+ end
35
+ end
36
+
37
+ context 'when proxy_conf is "proxy.example.com:foo"' do
38
+ should 'returns ["proxy.example.com", nil]' do
39
+ assert_equal ["proxy.example.com", nil], @cpr.send(:parse_proxy, "proxy.example.com:foo")
40
+ end
41
+ end
42
+ end
43
+
44
+ context '#title_and_description' do
45
+ setup do
46
+ @cpr = CreatePullRequest.new nil
47
+ def @cpr.title_from_branch; 'title_from_branch'; end
48
+ def @cpr.git_commit_messages; 'git_commit_messages'; end
49
+ @options = Struct.new(:title, :description)
50
+ end
51
+
52
+ context 'with no options' do
53
+ should 'sets default title and description' do
54
+ title, descr = @cpr.send(:title_and_description, @options.new(nil, nil))
55
+ assert_equal title, 'title_from_branch'
56
+ assert_equal descr, 'git_commit_messages'
57
+ end
58
+ end
59
+
60
+ context 'with title option' do
61
+ should 'sets custom title and default description' do
62
+ title, descr = @cpr.send(:title_and_description, @options.new('custom title', nil))
63
+ assert_equal title, 'custom title'
64
+ assert_equal descr, 'git_commit_messages'
65
+ end
66
+ end
67
+
68
+ context 'with description option' do
69
+ should 'sets default title and custom description' do
70
+ title, descr = @cpr.send(:title_and_description, @options.new(nil, 'custom description'))
71
+ assert_equal title, 'title_from_branch'
72
+ assert_equal descr, 'custom description'
73
+ end
74
+ end
75
+
76
+ context 'with both title and description options' do
77
+ should 'sets custom title and description' do
78
+ title, descr = @cpr.send(:title_and_description, @options.new('custom title', 'custom description'))
79
+ assert_equal title, 'custom title'
80
+ assert_equal descr, 'custom description'
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,96 @@
1
+ require 'helper'
2
+
3
+ include Atlassian::Stash
4
+ include Atlassian::Stash::Git
5
+
6
+ class TestGit < Minitest::Test
7
+
8
+ should "extract remote with ssh remote" do
9
+ Atlassian::Stash::Git.stubs(:get_remotes).returns(
10
+ "origin ssh://git@stash.atlassian.com:7999/STASH/stash.git (fetch)
11
+ origin ssh://git@stash.atlassian.com:7999/STASH/stash.git (push)"
12
+ )
13
+ assert_equal 'ssh://git@stash.atlassian.com:7999/STASH/stash.git', Atlassian::Stash::Git.get_remote_url
14
+ end
15
+
16
+ should "extract push remote with different fetch and push urls" do
17
+ Atlassian::Stash::Git.stubs(:get_remotes).returns(
18
+ "origin ssh://git@github.com/~sebr/stash.git (fetch)
19
+ origin ssh://git@stash.atlassian.com:7999/STASH/stash.git (push)"
20
+ )
21
+ assert_equal 'ssh://git@stash.atlassian.com:7999/STASH/stash.git', Atlassian::Stash::Git.get_remote_url
22
+ end
23
+
24
+ should "extract remote with http remote" do
25
+ Atlassian::Stash::Git.stubs(:get_remotes).returns(
26
+ "origin http://adam@sonoma:7990/stash/scm/QA/stash.git (fetch)
27
+ origin http://adam@sonoma:7990/stash/scm/QA/stash.git (push)"
28
+ )
29
+ assert_equal 'http://adam@sonoma:7990/stash/scm/QA/stash.git', Atlassian::Stash::Git.get_remote_url
30
+ end
31
+
32
+ should "extract remote with multiple remote urls" do
33
+ Atlassian::Stash::Git.stubs(:get_remotes).returns(
34
+ "bitbucket git@bitbucket.org:atlassian/stash-command-line-tools.git (fetch)
35
+ bitbucket git@bitbucket.org:atlassian/stash-command-line-tools.git (push)
36
+ kostya http://admin@kostya:7990/scm/CA/cylon.git (fetch)
37
+ kostya http://admin@kostya:7990/scm/CA/cylon.git (push)
38
+ local http://delirium:7990/git/STASH/stash.git (fetch)
39
+ local http://delirium:7990/git/STASH/stash.git (push)
40
+ origin ssh://git@stash.atlassian.com:7999/STASH/stash.git (fetch)
41
+ origin ssh://git@stash.atlassian.com:7999/STASH/stash.git (push)
42
+ seb http://adam@sonoma:7990/stash/scm/QA/stash.git (fetch)
43
+ seb http://adam@sonoma:7990/stash/scm/QA/stash.git (push)
44
+ upstream http://github-enterprise-11-10/stash/stash.git (fetch)
45
+ upstream http://github-enterprise-11-10/stash/stash.git (push)")
46
+ assert_equal 'ssh://git@stash.atlassian.com:7999/STASH/stash.git', Atlassian::Stash::Git.get_remote_url
47
+ end
48
+
49
+ should "extract custom remote with multiple remote urls" do
50
+ Atlassian::Stash::Git.stubs(:get_remotes).returns(
51
+ "bitbucket git@bitbucket.org:atlassian/stash-command-line-tools.git (fetch)
52
+ bitbucket git@bitbucket.org:atlassian/stash-command-line-tools.git (push)
53
+ kostya http://admin@kostya:7990/scm/CA/cylon.git (fetch)
54
+ kostya http://admin@kostya:7990/scm/CA/cylon.git (push)
55
+ local http://delirium:7990/git/STASH/stash.git (fetch)
56
+ local http://delirium:7990/git/STASH/stash.git (push)
57
+ origin ssh://git@stash.atlassian.com:7999/STASH/stash.git (fetch)
58
+ origin ssh://git@stash.atlassian.com:7999/STASH/stash.git (push)
59
+ upstream ssh://git@stash.atlassian.com:7999/ATLASSIAN/stash.git (fetch)
60
+ upstream ssh://git@stash.atlassian.com:7999/ATLASSIAN/stash.git (push)
61
+ seb http://adam@sonoma:7990/stash/scm/QA/stash.git (fetch)
62
+ seb http://adam@sonoma:7990/stash/scm/QA/stash.git (push)
63
+ upstream http://github-enterprise-11-10/stash/stash.git (fetch)
64
+ upstream http://github-enterprise-11-10/stash/stash.git (push)")
65
+ assert_equal 'ssh://git@stash.atlassian.com:7999/ATLASSIAN/stash.git', Atlassian::Stash::Git.get_remote_url('upstream')
66
+ end
67
+
68
+ should "repo with no remotes returns nil" do
69
+ Atlassian::Stash::Git.stubs(:get_remotes).returns("")
70
+ assert_equal nil, Atlassian::Stash::Git.get_remote_url
71
+ end
72
+
73
+ should "repo with unfound remote returns nil" do
74
+ Atlassian::Stash::Git.stubs(:get_remotes).returns(
75
+ "bitbucket git@bitbucket.org:atlassian/stash-command-line-tools.git (fetch)
76
+ bitbucket git@bitbucket.org:atlassian/stash-command-line-tools.git (push)"
77
+ )
78
+ assert_equal nil, Atlassian::Stash::Git.get_remote_url('origin')
79
+ end
80
+
81
+ should "branches are matched" do
82
+ Atlassian::Stash::Git.stubs(:get_branches).returns(
83
+ " feature
84
+ temp
85
+ * master
86
+ remotes/origin/master
87
+ remotes/origin/release/v1.0
88
+ remotes/origin/feature/awesome
89
+ remotes/upstream/master
90
+ remotes/upstream/release/v1.0
91
+ remotes/upstream/feature/Issue7")
92
+ assert_equal true, Atlassian::Stash::Git.is_branch?('master')
93
+ assert_equal true, Atlassian::Stash::Git.is_branch?('remotes/upstream/master')
94
+ end
95
+
96
+ end