maguro 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +102 -0
- data/LICENSE.txt +22 -0
- data/README.md +77 -0
- data/Rakefile +2 -0
- data/bin/maguro +18 -0
- data/lib/maguro.rb +9 -0
- data/lib/maguro/app_generator.rb +113 -0
- data/lib/maguro/bitbucket.rb +185 -0
- data/lib/maguro/cli.rb +10 -0
- data/lib/maguro/features.rb +389 -0
- data/lib/maguro/gemfile.rb +14 -0
- data/lib/maguro/github.rb +23 -0
- data/lib/maguro/heroku.rb +45 -0
- data/lib/maguro/keychain.rb +53 -0
- data/lib/maguro/version.rb +7 -0
- data/maguro.gemspec +27 -0
- data/spec/maguro/app_generator_spec.rb +46 -0
- data/spec/maguro/bitbucket_spec.rb +46 -0
- data/spec/spec_helper.rb +89 -0
- data/templates/home_controller.rb +4 -0
- data/templates/home_index.html.erb +2 -0
- metadata +145 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ddeb4fe9eb84bdeb224b00749cd640703f104dd4
|
4
|
+
data.tar.gz: 5912a8b3ad6fa2f659dc7eb0ed4c380914f677d2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 007ce4f75281f70fe5c536cb3513259243a2119edd518ed665614b65312530fbe05c6ef7671ef3d498de67545056a171f3c9a0eb288acdea1f4faaefe433fd81
|
7
|
+
data.tar.gz: e148cb85c274c7f13d0f42c0839ab88c71d2648da655dc297d5ff1f508e9f249545faab453ef438aca1eca05afd97951cb0dd9199f83e9679af110d1de1fcee0
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
magurogemset
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.2.0
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
maguro (0.0.1)
|
5
|
+
rails (= 4.1.8)
|
6
|
+
thor (~> 0.19)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
actionmailer (4.1.8)
|
12
|
+
actionpack (= 4.1.8)
|
13
|
+
actionview (= 4.1.8)
|
14
|
+
mail (~> 2.5, >= 2.5.4)
|
15
|
+
actionpack (4.1.8)
|
16
|
+
actionview (= 4.1.8)
|
17
|
+
activesupport (= 4.1.8)
|
18
|
+
rack (~> 1.5.2)
|
19
|
+
rack-test (~> 0.6.2)
|
20
|
+
actionview (4.1.8)
|
21
|
+
activesupport (= 4.1.8)
|
22
|
+
builder (~> 3.1)
|
23
|
+
erubis (~> 2.7.0)
|
24
|
+
activemodel (4.1.8)
|
25
|
+
activesupport (= 4.1.8)
|
26
|
+
builder (~> 3.1)
|
27
|
+
activerecord (4.1.8)
|
28
|
+
activemodel (= 4.1.8)
|
29
|
+
activesupport (= 4.1.8)
|
30
|
+
arel (~> 5.0.0)
|
31
|
+
activesupport (4.1.8)
|
32
|
+
i18n (~> 0.6, >= 0.6.9)
|
33
|
+
json (~> 1.7, >= 1.7.7)
|
34
|
+
minitest (~> 5.1)
|
35
|
+
thread_safe (~> 0.1)
|
36
|
+
tzinfo (~> 1.1)
|
37
|
+
arel (5.0.1.20140414130214)
|
38
|
+
builder (3.2.2)
|
39
|
+
diff-lcs (1.2.5)
|
40
|
+
erubis (2.7.0)
|
41
|
+
hike (1.2.3)
|
42
|
+
i18n (0.6.11)
|
43
|
+
json (1.8.1)
|
44
|
+
mail (2.6.3)
|
45
|
+
mime-types (>= 1.16, < 3)
|
46
|
+
mime-types (2.4.3)
|
47
|
+
minitest (5.4.3)
|
48
|
+
multi_json (1.10.1)
|
49
|
+
rack (1.5.2)
|
50
|
+
rack-test (0.6.2)
|
51
|
+
rack (>= 1.0)
|
52
|
+
rails (4.1.8)
|
53
|
+
actionmailer (= 4.1.8)
|
54
|
+
actionpack (= 4.1.8)
|
55
|
+
actionview (= 4.1.8)
|
56
|
+
activemodel (= 4.1.8)
|
57
|
+
activerecord (= 4.1.8)
|
58
|
+
activesupport (= 4.1.8)
|
59
|
+
bundler (>= 1.3.0, < 2.0)
|
60
|
+
railties (= 4.1.8)
|
61
|
+
sprockets-rails (~> 2.0)
|
62
|
+
railties (4.1.8)
|
63
|
+
actionpack (= 4.1.8)
|
64
|
+
activesupport (= 4.1.8)
|
65
|
+
rake (>= 0.8.7)
|
66
|
+
thor (>= 0.18.1, < 2.0)
|
67
|
+
rake (10.3.2)
|
68
|
+
rspec (3.1.0)
|
69
|
+
rspec-core (~> 3.1.0)
|
70
|
+
rspec-expectations (~> 3.1.0)
|
71
|
+
rspec-mocks (~> 3.1.0)
|
72
|
+
rspec-core (3.1.7)
|
73
|
+
rspec-support (~> 3.1.0)
|
74
|
+
rspec-expectations (3.1.2)
|
75
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
76
|
+
rspec-support (~> 3.1.0)
|
77
|
+
rspec-mocks (3.1.3)
|
78
|
+
rspec-support (~> 3.1.0)
|
79
|
+
rspec-support (3.1.2)
|
80
|
+
sprockets (2.11.3)
|
81
|
+
hike (~> 1.2)
|
82
|
+
multi_json (~> 1.0)
|
83
|
+
rack (~> 1.0)
|
84
|
+
tilt (~> 1.1, != 1.3.0)
|
85
|
+
sprockets-rails (2.2.1)
|
86
|
+
actionpack (>= 3.0)
|
87
|
+
activesupport (>= 3.0)
|
88
|
+
sprockets (>= 2.8, < 4.0)
|
89
|
+
thor (0.19.1)
|
90
|
+
thread_safe (0.3.4)
|
91
|
+
tilt (1.4.1)
|
92
|
+
tzinfo (1.2.2)
|
93
|
+
thread_safe (~> 0.1)
|
94
|
+
|
95
|
+
PLATFORMS
|
96
|
+
ruby
|
97
|
+
|
98
|
+
DEPENDENCIES
|
99
|
+
bundler (~> 1.6)
|
100
|
+
maguro!
|
101
|
+
rake
|
102
|
+
rspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Haji Furukawa
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# Maguro
|
2
|
+
|
3
|
+
![alt tag](http://hajimefurukawa.com/random/img/maguro_sushi.jpg)
|
4
|
+
|
5
|
+
Maguro is the base Rails application used at [Bottega8](http://www.bottega8.com/).
|
6
|
+
|
7
|
+
It's goal is to do all the boring configuration of setting up a new project for you automatically,
|
8
|
+
so you can get to the fun development part in seconds instead of hours.
|
9
|
+
|
10
|
+
## What does the template do?
|
11
|
+
|
12
|
+
Maguro will create a basic Rails project that is optimized for Bottega8's workflow by:
|
13
|
+
|
14
|
+
1. Saving RVM configuration files
|
15
|
+
1. Creating a basic README.md
|
16
|
+
1. Setting up local git repository, gitinit file, and development branch
|
17
|
+
1. Generating app_environment_variables.rb for custom environment variables
|
18
|
+
1. Removing Turbolinks
|
19
|
+
1. Including RSpec, capybara, database_cleaner, factory_girl, and other gems for testing
|
20
|
+
1. Using PostgreSQL as the database and generating database.yml
|
21
|
+
|
22
|
+
Optionally, Maguro can also
|
23
|
+
|
24
|
+
1. Create a Heroku application for staging and production environments
|
25
|
+
1. Create a Git repository on Github.com, and pushing the newly-created Rails project to it
|
26
|
+
1. Create a Git repository on BitBucket.org, and pushing the newly-created Rails project to it
|
27
|
+
1. Securely store BitBucket.org credentials in the OS X keychain for convenience
|
28
|
+
1. Create a local postgres database for the project
|
29
|
+
|
30
|
+
## Gem Prerequisites
|
31
|
+
|
32
|
+
Before running Maguro:
|
33
|
+
|
34
|
+
1. Install [PostgreSQL for OS X](http://www.postgresql.org/download/macosx/)
|
35
|
+
1. Install Ruby. We recommend using the [Ruby Version Manager](http://rvm.io/rvm/install)
|
36
|
+
|
37
|
+
|
38
|
+
Optional:
|
39
|
+
|
40
|
+
1. [Heroku toolbelt](https://toolbelt.heroku.com/) if you want to automatically deploy to heroku.
|
41
|
+
1. [Hub](https://github.com/github/hub) if you want to create a remote repository on github.
|
42
|
+
`brew install hub` with [homebrew](http://brew.sh/).
|
43
|
+
1. OSX Keychain if you want to save your bitbucket credentials.
|
44
|
+
|
45
|
+
## Gem Usage
|
46
|
+
|
47
|
+
Install the gem:
|
48
|
+
|
49
|
+
`gem install maguro`
|
50
|
+
|
51
|
+
Create a new app:
|
52
|
+
|
53
|
+
`maguro new $APP_NAME`
|
54
|
+
|
55
|
+
### Detailed Usage
|
56
|
+
|
57
|
+
1. Switch to directory where new project will live. E.g. `cd ~/Desktop/projects`
|
58
|
+
1. Install the maguro gem `gem install maguro`
|
59
|
+
1. Generate the new project: `maguro new $APP_NAME`
|
60
|
+
1. Open config/database.yml and replace `username` with the same username when setting up Postgres
|
61
|
+
1. Run `rake db:create db:migrate`
|
62
|
+
|
63
|
+
|
64
|
+
## Development and testing steps
|
65
|
+
|
66
|
+
To make local changes to this gem, clone this repository then:
|
67
|
+
|
68
|
+
1. Clone this repository
|
69
|
+
1. Run `bundle install` to install development dependencies
|
70
|
+
1. Develop/modify the source code
|
71
|
+
1. Run unit and integration tests with `rspec`
|
72
|
+
1. Build the gem `gem build maguro.gemspec`
|
73
|
+
1. Switch to the directory where you want to create a new project. E.g. `cd ~/Desktop/projects`
|
74
|
+
1. Install the gem `gem install ./maguro-0.0.1.gem`
|
75
|
+
1. Follow instructions in the section `Gem Usage`, i.e. `maguro new [APP_NAME]`
|
76
|
+
|
77
|
+
|
data/Rakefile
ADDED
data/bin/maguro
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
|
4
|
+
# read about this someplace on stackoverflow so that we cna run this file directly and debug
|
5
|
+
# instead of having to rebuild and run the gem.
|
6
|
+
lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
|
7
|
+
$LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
|
8
|
+
|
9
|
+
require 'maguro'
|
10
|
+
|
11
|
+
# required to set our custom AppGenerator source_path to the Rail's AppGenerator
|
12
|
+
# so it can find all default the template files.
|
13
|
+
templates_root = File.expand_path(File.join("..", "templates"), File.dirname(__FILE__))
|
14
|
+
Maguro::AppGenerator.source_root templates_root
|
15
|
+
Maguro::AppGenerator.source_paths << Rails::Generators::AppGenerator.source_root
|
16
|
+
|
17
|
+
#Start our custom CLI
|
18
|
+
Maguro::Cli.start(ARGV)
|
data/lib/maguro.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/rails/app/app_generator'
|
3
|
+
|
4
|
+
module Maguro
|
5
|
+
class AppGenerator < Rails::Generators::AppGenerator
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
class_option :heroku, type: :boolean, aliases: '--hh',
|
10
|
+
desc: 'Create a production and staging heroku application'
|
11
|
+
|
12
|
+
class_option :bitbucket, type: :boolean, aliases: '--bb',
|
13
|
+
desc: 'Create a bitbucket project and push to it.'
|
14
|
+
|
15
|
+
class_option :github, type: :boolean, aliases: '--gh',
|
16
|
+
desc: 'Create a github project and push to it.'
|
17
|
+
|
18
|
+
class_option :organization, type: :string, aliases: '-o',
|
19
|
+
desc: 'Pass in your organization name to be used by heroku and bitbucket'
|
20
|
+
|
21
|
+
class_option :'database-username', type: :string, aliases: '--du',
|
22
|
+
desc: 'Add a database username'
|
23
|
+
|
24
|
+
class_option :'database-password', type: :string, aliases: '--dp',
|
25
|
+
desc: 'Add a database password'
|
26
|
+
|
27
|
+
# Overriding Rails::Generators::AppGenerator#finish_template.
|
28
|
+
# Allows maguro to do stuff before the default rails generator is run.
|
29
|
+
#
|
30
|
+
def initialize(*args)
|
31
|
+
super
|
32
|
+
|
33
|
+
check_ruby_version
|
34
|
+
|
35
|
+
# Thor's option hash is frozen. Unfreeze so we can update our own variables on it.
|
36
|
+
# Risk: Don't accidentally modify options you didn't mean to!
|
37
|
+
self.options = options.dup
|
38
|
+
|
39
|
+
set_custom_options
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
# Overriding Rails::Generators::AppGenerator#finish_template.
|
44
|
+
# This will run our maguro customizations after all of the default rails customizations.
|
45
|
+
def finish_template
|
46
|
+
Maguro::Features.new(builder).run_all_updates
|
47
|
+
|
48
|
+
super
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
def check_ruby_version
|
54
|
+
if ::RUBY_VERSION != Maguro::RUBY_VERSION
|
55
|
+
raise Thor::Error, "You are using ruby version #{::RUBY_VERSION}. Maguro requires ruby version #{Maguro::RUBY_VERSION}. (e.g. rvm use #{Maguro::RUBY_VERSION})."
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def set_custom_options
|
60
|
+
|
61
|
+
#skip heroku and bitbucket if --pretend is passed.
|
62
|
+
if options[:pretend]
|
63
|
+
options[:heroku] = false
|
64
|
+
options[:bitbucket] = false
|
65
|
+
options[:github] = false
|
66
|
+
else
|
67
|
+
# Prompt user if they haven't passed in a value for heroku, bitbucket options.
|
68
|
+
if options[:heroku].nil?
|
69
|
+
options[:heroku] = builder.yes?('Setup Heroku (y/n)?')
|
70
|
+
end
|
71
|
+
if options[:bitbucket].nil?
|
72
|
+
options[:bitbucket] = builder.yes?('Setup BitBucket repo (y/n)?')
|
73
|
+
end
|
74
|
+
if options[:github].nil?
|
75
|
+
options[:github] = builder.yes?('Setup Github repo (y/n)?')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
if options[:bitbucket] && options[:github]
|
80
|
+
raise Thor::Error, "Can't set up both bitbucket and github :p. (Select one)"
|
81
|
+
end
|
82
|
+
|
83
|
+
# only worry about setting organization if we are using heroku or bitbucket
|
84
|
+
if options[:heroku] || options[:bitbucket] || options[:github]
|
85
|
+
set_organization
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
KEYCHAIN_ORGANIZATION='organization'
|
91
|
+
|
92
|
+
def set_organization
|
93
|
+
saved_organization = Keychain.retrieve_account(KEYCHAIN_ORGANIZATION)
|
94
|
+
saved_organization = saved_organization[:password] if saved_organization
|
95
|
+
|
96
|
+
if options[:organization]
|
97
|
+
org_output = saved_organization ? saved_organization : "<none>"
|
98
|
+
|
99
|
+
if yes?("Save organization '#{options[:organization]}' as default (y/n)? (current default: #{org_output})")
|
100
|
+
Keychain.add_account(KEYCHAIN_ORGANIZATION, KEYCHAIN_ORGANIZATION, options[:organization])
|
101
|
+
end
|
102
|
+
elsif saved_organization
|
103
|
+
if yes?("Use saved organization, #{saved_organization} (y/n)?")
|
104
|
+
options[:organization] = saved_organization
|
105
|
+
else
|
106
|
+
raise Thor::InvocationError, "Organization was not set. Please set organization with '-o ORGANIZATION'"
|
107
|
+
end
|
108
|
+
else
|
109
|
+
raise Thor::InvocationError, "Organization was not set. Please set organization with '-o ORGANIZATION'"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'uri'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module Maguro
|
7
|
+
class Bitbucket
|
8
|
+
protected
|
9
|
+
attr_accessor :username, :password
|
10
|
+
|
11
|
+
public
|
12
|
+
attr_reader :builder, :app_name, :organization
|
13
|
+
|
14
|
+
BITBUCKET = "bitbucket.org"
|
15
|
+
API_BASE = "https://api.bitbucket.org/2.0"
|
16
|
+
|
17
|
+
def initialize(builder, app_name, organization)
|
18
|
+
@builder = builder
|
19
|
+
@app_name = app_name
|
20
|
+
@organization = organization
|
21
|
+
self.username = nil
|
22
|
+
self.password = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def git_url
|
26
|
+
if @git_url.nil?
|
27
|
+
path = "#{API_BASE}/repositories/#{organization}/#{app_name}"
|
28
|
+
response = bitbucket_api(path, Net::HTTP::Get)
|
29
|
+
|
30
|
+
if response.code == "200"
|
31
|
+
@git_url = JSON.parse(response.body)["links"]["clone"].find{|i| i["name"] == "https"}["href"]
|
32
|
+
else
|
33
|
+
raise "Could not retrieve Git url for project #{app_name}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
@git_url
|
37
|
+
end
|
38
|
+
|
39
|
+
def create_repo
|
40
|
+
options = {
|
41
|
+
scm: 'git',
|
42
|
+
name: app_name,
|
43
|
+
is_private: true,
|
44
|
+
fork_policy: 'no_public_forks',
|
45
|
+
language: 'ruby'
|
46
|
+
}
|
47
|
+
|
48
|
+
path = "#{API_BASE}/repositories/#{organization}/#{app_name}"
|
49
|
+
response = bitbucket_api(path, Net::HTTP::Post, options)
|
50
|
+
|
51
|
+
if response.code == "200"
|
52
|
+
# Success
|
53
|
+
puts "Successfully created repository for #{app_name}"
|
54
|
+
else
|
55
|
+
raise "Could not create Git repository for project #{app_name}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def delete_repo
|
60
|
+
path = "#{API_BASE}/repositories/#{organization}/#{app_name}"
|
61
|
+
success_code = 204
|
62
|
+
response = bitbucket_api(path, Net::HTTP::Delete, {}, success_code)
|
63
|
+
raise "Could not delete repository." if response.code != success_code.to_s
|
64
|
+
puts "Successfully deleted repository: '#{app_name}'"
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_repo
|
68
|
+
path = "#{API_BASE}/repositories/#{organization}/#{app_name}"
|
69
|
+
response = bitbucket_api(path, Net::HTTP::Get)
|
70
|
+
|
71
|
+
# Do not raise on error, so that this method can be used
|
72
|
+
# to query the existence of a repository
|
73
|
+
return nil if response.code != "200"
|
74
|
+
|
75
|
+
JSON.parse(response.body)
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
private
|
80
|
+
def bitbucket_api(path, method, options = {}, expected_http_code = 200)
|
81
|
+
puts "Making request to API at: #{path} via #{method} with options: #{options}"
|
82
|
+
|
83
|
+
# TODO: Doug: do we want to enable this?
|
84
|
+
# First, try to read the username and password from the OS X Keychain,
|
85
|
+
# as stored by git credential-oskeychain
|
86
|
+
# if username.nil? || password.nil?
|
87
|
+
# output = %x[printf protocol=https\\\\nhost=#{BITBUCKET}\\\\n\\\\n | git credential-osxkeychain get]
|
88
|
+
# m = output.match("password=(.*)\n")
|
89
|
+
# self.password = m[1] if !m.nil?
|
90
|
+
# m = output.match("username=(.*)\n")
|
91
|
+
# self.username = m[1] if !m.nil?
|
92
|
+
# end
|
93
|
+
|
94
|
+
# Try to retrieve username and password directly from the OS X Keychain
|
95
|
+
did_get_password_from_keychain = false
|
96
|
+
if username.nil? || password.nil?
|
97
|
+
credentials = Keychain.retrieve_account(BITBUCKET)
|
98
|
+
if !credentials.nil?
|
99
|
+
self.username = credentials[:username]
|
100
|
+
self.password = credentials[:password]
|
101
|
+
did_get_password_from_keychain = true
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
tries = 0
|
106
|
+
response = nil
|
107
|
+
should_store_in_keychain = false
|
108
|
+
|
109
|
+
loop do
|
110
|
+
|
111
|
+
tries += 1
|
112
|
+
|
113
|
+
if username.nil? || password.nil?
|
114
|
+
|
115
|
+
# Prompt the user for password
|
116
|
+
puts ""
|
117
|
+
self.username = builder.ask "What is your BitBucket username?"
|
118
|
+
puts ""
|
119
|
+
# password = $stdin.noecho do
|
120
|
+
# ask "BitBucket password?"
|
121
|
+
# end
|
122
|
+
self.password = builder.ask "What is your BitBucket password?", :echo => false
|
123
|
+
puts ""
|
124
|
+
puts ""
|
125
|
+
|
126
|
+
if did_get_password_from_keychain || (builder.yes? "Do you want to store this BitBucket login info into the Keychain? (y/n)")
|
127
|
+
should_store_in_keychain = true
|
128
|
+
end
|
129
|
+
puts ""
|
130
|
+
end
|
131
|
+
|
132
|
+
url = URI.parse(path)
|
133
|
+
http = Net::HTTP.new(url.host, url.port)
|
134
|
+
http.use_ssl = (url.scheme == 'https')
|
135
|
+
|
136
|
+
request = method.new(url.path)
|
137
|
+
if !options.empty?
|
138
|
+
request["content-type"] = "application/json"
|
139
|
+
request.body = options.to_json
|
140
|
+
end
|
141
|
+
|
142
|
+
request.basic_auth username, password
|
143
|
+
|
144
|
+
response = http.request(request)
|
145
|
+
|
146
|
+
response_code = response.code.to_i
|
147
|
+
|
148
|
+
# Most REST calls return HTTP 200 on success.
|
149
|
+
# Some calls return another status code on success,
|
150
|
+
# E.g. DELETE returns 204
|
151
|
+
if response_code == expected_http_code # Success
|
152
|
+
Keychain.add_account(BITBUCKET, username, password) if should_store_in_keychain
|
153
|
+
return response
|
154
|
+
end
|
155
|
+
|
156
|
+
puts "Response code: #{response_code} message: #{response.message}"
|
157
|
+
if !response.body.empty?
|
158
|
+
message = JSON.parse(response.body)["error"]["message"]
|
159
|
+
detail = JSON.parse(response.body)["error"]["detail"]
|
160
|
+
puts "Error message: #{message}"
|
161
|
+
puts "Error detail: #{detail}" if !detail.nil?
|
162
|
+
end
|
163
|
+
|
164
|
+
break if tries >= 3 # Try no more than three times
|
165
|
+
break if response_code != 401 # Only retry when the username/password is incorrect
|
166
|
+
|
167
|
+
# Clear password, so the next iteration of the loop will prompt the user
|
168
|
+
if response_code == 401
|
169
|
+
self.username = nil
|
170
|
+
self.password = nil
|
171
|
+
|
172
|
+
if did_get_password_from_keychain
|
173
|
+
# If we got credentials from the Keychain, and authentication fails,
|
174
|
+
# clear the credentials from the keychain
|
175
|
+
Keychain.delete_account(BITBUCKET)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# The request was unsuccessful
|
181
|
+
response
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|