atlassian-stash-avisi 0.4.15

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cd4aa7e0c2c0f4fc7f9590c8a505a5fab6d70cd5
4
+ data.tar.gz: 9b22cd3452ff21e9978f39ccbf38c9edb6a5288e
5
+ SHA512:
6
+ metadata.gz: e9d1279424f61ba9c9d692ceb8a36b26669673b0212e4a4975b888cb695c1d9d1f3a613e78504ac75e1cdc656a0f9ebc642de298ad060c944b23190fb2d08b78
7
+ data.tar.gz: fe991aba491b3a95e26c1b079d98953ff4ea2cbfab56ab3e18af936e2078c30fc7d882ad9f7b622668e7d2b1fb39751939a83a324981a7d4ba4c959478409539
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,23 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ gem "git", "~> 1.2.5"
7
+ gem "json", "~> 1.7.5"
8
+ gem "commander", "~> 4.1.2"
9
+ gem "launchy", "~> 2.4.2"
10
+ gem 'ruby-keychain', :require => 'keychain'
11
+
12
+ #
13
+ # Add dependencies to develop your gem here.
14
+ # Include everything needed to run rake, tests, features, etc.
15
+ group :development do
16
+ gem "shoulda", ">= 0"
17
+ gem "rdoc", "~> 3.12"
18
+ gem "bundler", ">= 1.2.0"
19
+ gem "jeweler", "~> 2.0.0"
20
+ gem "rcov", ">= 0", :platforms => :ruby_18
21
+ gem "simplecov", ">= 0", :platforms => :ruby_19, :require => "false"
22
+ gem "minitest", ">= 0", :platforms => :ruby_19
23
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Seb Ruiz
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,114 @@
1
+ # Atlassian Stash Command Line Tools
2
+
3
+ ## Installing this tool
4
+ This command line helper for Stash is written in Ruby and is deployed as a [Ruby Gem](https://rubygems.org/gems/atlassian-stash/). Installation is easy, simply run the following command
5
+
6
+ ```
7
+ #!text
8
+ $> gem install atlassian-stash
9
+ ```
10
+
11
+ (Protip: you might need to `sudo`)
12
+
13
+ Once the gem is installed, the command `stash` will be in your `$PATH`
14
+
15
+ ## Configuration and usage
16
+ Run `stash configure`. This will prompt for details about your Stash instance. If no password is provided, then you will be prompted for a password when executing commands to Stash. Currently, the password is stored in plain text in a configuration file, `~/.stashconfig.yml` which is protected with a permission bit of `0600`.
17
+
18
+ ### Creating a pull request
19
+ Use the `pull-request` command to create a pull request in Stash. For example:
20
+
21
+ ```
22
+ #!text
23
+ $> stash pull-request topicBranch master @michael
24
+ Create a pull request from branch 'topicBranch' into 'master' with 'michael' added as a reviewer
25
+ ```
26
+
27
+ See the usage for command details
28
+
29
+ ```
30
+ #!text
31
+ $> stash help pull-request
32
+ ```
33
+
34
+ ### Opening the Stash web UI
35
+ Use the `browse` command to open the Stash UI for your repository in the browser.
36
+
37
+ ```
38
+ #!text
39
+ $> stash browse -b develop
40
+ Open the browser at the Stash repository page for the branch 'develop'
41
+ ```
42
+
43
+ For more options, see the help
44
+
45
+ ```
46
+ #!text
47
+ stash help browse
48
+ ```
49
+
50
+ ## Configuration options
51
+
52
+ Running `stash configure` will prepopulate `~/.stashconfig.yml` with a variety of options. Complete options are:
53
+
54
+ ```
55
+ #!yaml
56
+ username: seb # username to connect to stash server.
57
+ password: s3cr3t # password for user. If ommitted, you will be prompted at the terminal when making a request to Stash
58
+ stash_url: https://stash.server.com # fully qualified stash url
59
+ open: true # opens newly created pull requests in the browser
60
+ ssl_no_verify: true # do not check ssl certificates for the configured stash server
61
+ ```
62
+
63
+ ## Troubleshooting
64
+ Q: I installed the gem, but the `stash` command doesn't work.
65
+ A: Do you have another command called `stash` or do you have an alias? Have a look where the command maps to
66
+
67
+ ```
68
+ #!text
69
+ $> which -a stash
70
+ ```
71
+
72
+ Then check the value of your $PATH
73
+
74
+ ## I want to contribute
75
+ Thanks! Please [fork this project](https://bitbucket.org/atlassian/stash-command-line-tools/fork) and create a pull request to submit changes back to the original project.
76
+
77
+ ### Build instructions
78
+ Building this gem is easy. To get started, run the following commands:
79
+
80
+ ```
81
+ #!text
82
+ $> gem install bundler
83
+ $> bundle install
84
+ ```
85
+
86
+ Now start hacking, and run the stash command by invoking `./bin/stash command`
87
+
88
+ ### Testing
89
+
90
+ Easy:
91
+
92
+ ```
93
+ $> rake test
94
+ ```
95
+
96
+ ### Releasing
97
+
98
+ #### Bumping versions
99
+
100
+ Use `rake version`:
101
+
102
+ ```
103
+ version -- displays the current version
104
+ version:bump:major -- bump the major version by 1
105
+ version:bump:minor -- bump the a minor version by 1
106
+ version:bump:patch -- bump the patch version by 1
107
+ version:write -- writes out an explicit version
108
+ ```
109
+
110
+ #### Releasing
111
+
112
+ ```
113
+ $> rake release
114
+ ```
@@ -0,0 +1,69 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "atlassian-stash-avisi"
18
+ gem.homepage = "https://insight.avisi.nl/stash/projects/TPL/repos/stash-command-line-tools"
19
+ gem.license = "MIT"
20
+ gem.summary = "Command line tools for Atlassian Stash Avisi version"
21
+ gem.description = "Provides convenient functions for interacting with Atlassian Stash through the command line"
22
+ gem.email = "m.diepenbroek@avisi.nl"
23
+ gem.authors = ["Seb Ruiz", "Maik Diepenbroek"]
24
+ # dependencies defined in Gemfile
25
+ gem.executables = ["stash"]
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rake/testtask'
30
+ Rake::TestTask.new(:test) do |test|
31
+ test.libs << 'lib' << 'test'
32
+ test.pattern = 'test/**/test_*.rb'
33
+ test.verbose = true
34
+ end
35
+
36
+ task :default => :test
37
+
38
+ begin
39
+ require 'rcov/rcovtask'
40
+
41
+ Rcov::RcovTask.new do |test|
42
+ test.libs << 'test'
43
+ test.pattern = 'test/**/test_*.rb'
44
+ test.verbose = true
45
+ test.rcov_opts << '--exclude "gems/*"'
46
+ end
47
+ rescue LoadError => e
48
+ end
49
+
50
+ begin
51
+ require "simplecov"
52
+
53
+ desc "Execute tests with coverage report"
54
+ task :simplecov do
55
+ ENV["COVERAGE"]="true"
56
+ Rake::Task["test"].execute
57
+ end
58
+ rescue LoadError
59
+ end
60
+
61
+ require 'rdoc/task'
62
+ Rake::RDocTask.new do |rdoc|
63
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
64
+
65
+ rdoc.rdoc_dir = 'rdoc'
66
+ rdoc.title = "atlassian-stash #{version}"
67
+ rdoc.rdoc_files.include('README*')
68
+ rdoc.rdoc_files.include('lib/**/*.rb')
69
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.4.15
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require File.dirname(__FILE__) + "/../lib/stash_cli"
5
+ require 'commander/import'
6
+ require 'yaml'
7
+ require 'launchy'
8
+ require 'pathname'
9
+ require 'base64'
10
+
11
+ program :name, "Atlassian Stash CLI"
12
+ program :version, Atlassian::Stash::Version::STRING
13
+ program :description, "Provides convenient functions for interacting with Atlassian Stash through the command line"
14
+
15
+ include Atlassian::Stash
16
+ include Atlassian::Stash::Git
17
+
18
+
19
+ $configFile = File.join(ENV['HOME'], ".stashconfig.yml")
20
+
21
+ def load_config
22
+ raise "No Stash configuration found; please run configure" unless File.exists? $configFile
23
+ config = YAML.load_file($configFile)
24
+ raise "Stash configuration file is incomplete, please re-run configure" unless config['stash_url']
25
+ # config.merge! repo_config
26
+ config
27
+ end
28
+
29
+ # def repo_config
30
+ # return @repo_config if @repo_config
31
+ # ascender = Pathname.pwd.to_enum(:ascend)
32
+ # config_path = ascender.detect { |path| (path + '.stash').exist? }
33
+ # @repo_config = YAML.load_file(path + '.stash')
34
+ # @repo_config
35
+ # end
36
+
37
+ command 'configure' do |c|
38
+ c.syntax = 'configure'
39
+ c.description = 'Setup configuration details to your Stash instance'
40
+ c.example 'stash configure --username sebr --password s3cre7 --stash_url http://stash.mycompany.com', 'Setup Stash CLI with credentials to the Stash server'
41
+ c.option '--username user', String, 'Writes your Stash username to the configuration file'
42
+ c.option '--password password', String, 'Writes your Stash user password to the configuration file. If omitted, password will be prompted to be entered'
43
+ c.option '--stashUrl', String, 'Writes the Stash server url to the configuration file'
44
+ c.option '--remote', String, 'Pull requests will be created in the Stash repository specified by the given remote'
45
+ c.action do |args, options|
46
+ useKeyChain = options.useKeyChain ? options.useKeyChain : ask("Use the keychain to authenticate with stash (y/n)")
47
+ if useKeyChain.downcase != "y"
48
+ username = options.username ? options.username : ask("Stash Username: ")
49
+ password = options.password ? options.password : ask("Stash Password (optional): ") { |q| q.echo = "*" }
50
+ else
51
+ username = ""
52
+ password = ""
53
+ end
54
+ stashUrl = options.stashUrl ? options.stashUrl : ask("Stash URL: ")
55
+ remote = options.remote ? options.remote : ask("Remote (optional): ")
56
+ certificateFile = options.certificateFile ? options.certificateFile : ask("Absolute path to certificate file: (/Users/username/certificate.p12)")
57
+ certificatePassword = options.certificatePassword ? options.certificatePassword : ask("Certificate password: ") { |q| q.echo = "*"}
58
+
59
+ c = {
60
+ 'stash_url' => stashUrl.to_s
61
+ }
62
+
63
+ c['username'] = username.to_s unless username.empty?
64
+ c['password'] = password.to_s unless password.empty?
65
+ c['remote'] = remote.to_s unless remote.empty?
66
+ c['certificateFile'] = certificateFile.to_s unless certificateFile.empty?
67
+ c['certificatePassword'] = Base64.strict_encode64(certificatePassword.to_s)
68
+ c['ssl_no_verify'] = true
69
+
70
+ if useKeyChain.downcase == "y"
71
+ c['useKeyChain'] = true
72
+ else
73
+ c['useKeyChain'] = false
74
+ end
75
+
76
+ File.open($configFile, 'w') do |out|
77
+ YAML.dump(c, out)
78
+ end
79
+
80
+ File.chmod 0600, $configFile
81
+
82
+ create_git_alias if agree "Create a git alias 'git create-pull-request'? "
83
+ end
84
+ end
85
+
86
+ command 'pull-request' do |c|
87
+ def extract_reviewers(args = [])
88
+ default_reviewers = []
89
+ default_reviewers.concat args.collect { |user|
90
+ user[1..-1] if user.start_with?("@")
91
+ }.compact
92
+ end
93
+
94
+ c.syntax = 'pull-request [sourceBranch] targetBranch [@reviewer1 @reviewer2] [options]'
95
+ c.description = 'Create a pull request in Stash'
96
+ c.option '-d DESCRIPTION', '--description DESCRIPTION', String, 'Use the following description when creating the pull request'
97
+ c.option '-T TITLE', '--title TITLE', String, 'Use the following title when creating the pull request'
98
+ c.option '-r remote', '--remote remote', String, 'Creates the pull request in the Stash repository specified by the given remote'
99
+ c.option '-o', '--open', 'Open the created pull request page in a web browser'
100
+ c.example 'stash pull-request topicBranch master @michael', "Create a pull request from branch 'topicBranch' into 'master' with 'michael' added as a reviewer"
101
+ c.example 'stash pull-request master', "Create a pull request from the current git branch into 'master'"
102
+ c.example 'stash pull-request master -T "JIRA-1234 new feature" -d "Adds new feature as described in JIRA-1234"', "Create a pull request from the current git branch into 'master' with the title 'JIRA-1234 new feature' and description 'Adds new feature as described in JIRA-1234'"
103
+ c.action do |args, options|
104
+ if args.length == 0
105
+ command(:help).run('pull-request')
106
+ Process.exit
107
+ end
108
+
109
+ source = args.shift
110
+ if args.empty? or args.first.start_with?("@")
111
+ target = source
112
+ source = get_current_branch()
113
+ reviewers = extract_reviewers args
114
+ else
115
+ target = args.shift
116
+ reviewers = extract_reviewers args
117
+ end
118
+
119
+ ensure_within_git! do
120
+ cpr = CreatePullRequest.new(load_config)
121
+ cpr.create_pull_request source, target, reviewers, options
122
+ end
123
+ end
124
+ end
125
+
126
+ command 'browse' do |c|
127
+ c.syntax = 'browse [browse|commits|pull-requests]'
128
+ c.description = 'Open the Stash web ui for this repository'
129
+ c.option '-b branch', '--branch branch', String, 'Open the Stash web ui at the specified branch, tag or commit hash. Defaults to the current branch'
130
+ c.option '-r remote', '--remote remote', String, 'Creates the pull request in the Stash repository specified by the given remote'
131
+ c.example 'stash browse -b master', 'Open the files view for this repository at the current branch'
132
+ c.example 'stash browse -r upstream', 'Open the files view for the "upstream" remote repository'
133
+
134
+ c.action do |args, options|
135
+
136
+ tab = args.shift unless args.empty?
137
+
138
+ config = load_config
139
+ remote = options.remote || config['remote']
140
+ remote_url = get_remote_url(remote)
141
+
142
+ repoInfo = RepoInfo.create(config, remote_url)
143
+
144
+ branch = options.branch || get_current_branch
145
+
146
+ Launchy.open repoInfo.repoUrl(tab, branch)
147
+ end
148
+ end
149
+
150
+
151
+ default_command :help
152
+ program :help_formatter, :compact
153
+ program :help, 'Authors', 'Seb Ruiz <sruiz@atlassian.com>'
154
+ program :help, 'Website', 'https://bitbucket.org/atlassian/stash-command-line-tools'
155
+
156
+
157
+ # vim set ft=ruby
@@ -0,0 +1,36 @@
1
+
2
+
3
+ module Atlassian
4
+ module Stash
5
+ module Git
6
+ def get_current_branch
7
+ %x(git symbolic-ref HEAD)[/refs\/heads\/(.*)/, 1]
8
+ end
9
+
10
+ def is_in_git_repository?
11
+ system('git rev-parse')
12
+ end
13
+
14
+ def get_remotes
15
+ %x(git remote -v)
16
+ end
17
+
18
+ def get_remote_url(remote = 'origin')
19
+ origin = get_remotes.split("\n").collect { |r| r.strip }.grep(/^#{remote}.*\(push\)$/).first
20
+ URI.extract(origin).first
21
+ end
22
+
23
+ def ensure_within_git!
24
+ if is_in_git_repository?
25
+ yield
26
+ else
27
+ raise "fatal: Not a git repository"
28
+ end
29
+ end
30
+
31
+ def create_git_alias
32
+ %x(git config --global alias.create-pull-request "\!sh -c 'stash pull-request \\$0'")
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,163 @@
1
+ require 'json'
2
+ require 'net/https'
3
+ require 'uri'
4
+ require 'git'
5
+ require 'launchy'
6
+ require 'keychain'
7
+ require 'base64'
8
+
9
+ include Atlassian::Util::TextUtil
10
+
11
+ module Atlassian
12
+ module Stash
13
+ class CreatePullRequestResource
14
+ attr_accessor :resource
15
+
16
+ def initialize(projectKey, slug, title, description, reviewers, source, target)
17
+ repository = {
18
+ 'slug' => slug,
19
+ 'project' => {
20
+ 'key' => projectKey
21
+ }
22
+ }
23
+ fromRef = {
24
+ 'id' => source,
25
+ 'repository' => repository
26
+ }
27
+ toRef = {
28
+ 'id' => target,
29
+ 'repository' => repository
30
+ }
31
+ @resource = {
32
+ 'title' => title,
33
+ 'fromRef' => fromRef,
34
+ 'toRef' => toRef
35
+ }
36
+
37
+ @resource["description"] = description unless description.empty?
38
+
39
+ @resource["reviewers"] = reviewers.collect { |r|
40
+ {
41
+ 'user' => {
42
+ 'name' => r
43
+ }
44
+ }
45
+ } unless reviewers.empty?
46
+ end
47
+ end
48
+
49
+ class CreatePullRequest
50
+
51
+ def initialize(config)
52
+ @config = config
53
+ end
54
+
55
+ def create_pull_request(source, target, reviewers, options)
56
+
57
+ Process.exit if not target or not source
58
+
59
+ @source = source
60
+ @target = target
61
+
62
+ remote = get_remote_url(options.remote || @config["remote"])
63
+ repoInfo = RepoInfo.create(@config, remote)
64
+
65
+ title, description = title_and_description(options)
66
+
67
+ resource = CreatePullRequestResource.new(repoInfo.projectKey, repoInfo.slug, title, description, reviewers, @source, @target).resource
68
+ if(@config['useKeyChain'])
69
+ stashKeyChain = Keychain.internet_passwords.where({:server =>"insight.avisi.nl", :path => '/stash/login'} ).first
70
+
71
+ username = stashKeyChain.account
72
+ password = stashKeyChain.password
73
+ else
74
+ username = @config["username"]
75
+ password = @config["password"]
76
+ end
77
+ proxy_addr, proxy_port = parse_proxy(@config["proxy"])
78
+ if(!@config['useKeyChain'])
79
+ username = ask("Username: ") unless @config["username"]
80
+ password = ask("Password: ") { |q| q.echo = '*' } unless @config["password"]
81
+ end
82
+ uri = URI.parse(@config["stash_url"])
83
+ prPath = repoInfo.repoPath + '/pull-requests'
84
+
85
+ req = Net::HTTP::Post.new(uri.query.nil? ? "#{prPath}" : "#{prPath}?#{uri.query}", {'Content-Type' => 'application/json', 'Accept' => 'application/json'})
86
+ req.basic_auth username, password
87
+ req.body = resource.to_json
88
+ http = Net::HTTP.new(uri.host, uri.port, proxy_addr, proxy_port)
89
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @config["ssl_no_verify"]
90
+ http.use_ssl = uri.scheme.eql?("https")
91
+
92
+
93
+
94
+ if not @config["certificateFile"].empty?
95
+ p12 = OpenSSL::PKCS12.new(File.read(@config["certificateFile"]), Base64.strict_decode64(@config['certificatePassword']))
96
+ http.cert = p12.certificate
97
+ http.key = p12.key
98
+ end
99
+
100
+ response = http.start {|conn| conn.request(req) }
101
+
102
+ if not response.is_a? Net::HTTPCreated
103
+ responseBody = JSON.parse(response.body)
104
+ if responseBody['errors']
105
+ responseBody['errors'].collect { |error|
106
+ puts error['message']
107
+ if error['reviewerErrors']
108
+ error['reviewerErrors'].collect { |revError|
109
+ puts revError['message']
110
+ }
111
+ end
112
+ }
113
+ elsif responseBody['message']
114
+ puts responseBody['message']
115
+ else
116
+ puts 'An unknown error occurred.'
117
+ puts response.code
118
+ puts response.body
119
+ end
120
+ else
121
+ responseBody = JSON.parse(response.body)
122
+ prUri = uri.clone
123
+ prUri.path = prPath + '/' + responseBody['id'].to_s
124
+ prUri.query = uri.query
125
+ puts prUri.to_s
126
+
127
+ if @config["open"] || options.open
128
+ Launchy.open prUri.to_s
129
+ end
130
+ end
131
+ end
132
+
133
+ private
134
+
135
+ def title_from_branch
136
+ convert_branch_name_to_sentence(@source) || "Merge '#{@source}' into '#{@target}'"
137
+ end
138
+
139
+ def git_commit_messages
140
+ @commit_messages ||= `git log --reverse --format=%s #{@target}..#{@source}`
141
+ end
142
+
143
+ def parse_proxy(conf)
144
+ return nil, nil unless conf
145
+
146
+ addr, port = conf.split(":")
147
+ if port =~ /\d+/
148
+ port = port.to_i
149
+ else
150
+ port = nil
151
+ end
152
+ [addr, port]
153
+ end
154
+
155
+ def title_and_description(options)
156
+ descr = (options.description or git_commit_messages)
157
+ title = (options.title or title_from_branch)
158
+
159
+ [title, descr]
160
+ end
161
+ end
162
+ end
163
+ end