bucket-cli 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 40c5f1a4499778d641fb6a1b843721593567ad5a
4
- data.tar.gz: 42a542e11a64d789a7822870bc56534f6b3ceab0
3
+ metadata.gz: e1e3681f9ff4782374b1160d5cb5233d5af92c5b
4
+ data.tar.gz: 760a5ebe6ca705b6e8f562f8880b63712f506e63
5
5
  SHA512:
6
- metadata.gz: 4e4205cf5d982a68596797778235cf000bdc7013c197b7eaebbc5255cadcc2dc3c1528e12cd198a484d263468330a27bc95218b0cbb07dcf727c3418fb077eeb
7
- data.tar.gz: 2fc5dc71f444b063efb848912f3ef2792308ef0ce9fa2f1a76205f9dc73881d48b642d94e41ed7b4f8612cc889aa226453c23aa13cebb802d566c7e7f617a39a
6
+ metadata.gz: 6cc1cdd1e06906714963ba2e9338a98a0be813df258e1cc13399709fee548ff25dcecee732e114e336083b0812f77180dd0c85738c7a5ff219b364ec32a9f3b9
7
+ data.tar.gz: 790ff1a30c0fbd0eaa8f19197ab4c1f085d955553dfe70468c6d596db06f0d3bf3a007bea443ad8893e631e64152e02f988cdf3b44803959571c46d271e2cc65
data/README.md CHANGED
@@ -1,24 +1,89 @@
1
1
  # Bucket
2
2
 
3
- TODO: Write a gem description
3
+ A Command Line Interface for [BitBucket](https://bitbucket.org).
4
+ *For now, only `git` is supported. Mercurial support is planned.*
4
5
 
5
6
  ## Installation
6
7
 
7
8
  Add this line to your application's Gemfile:
8
9
 
9
- gem 'bucket'
10
+ ~~~ sh
11
+ gem 'bucket-cli'
12
+ ~~~
10
13
 
11
14
  And then execute:
12
15
 
13
- $ bundle
16
+ ~~~ sh
17
+ $ bundle
18
+ ~~~
14
19
 
15
20
  Or install it yourself as:
16
21
 
17
- $ gem install bucket
22
+ ~~~ sh
23
+ $ gem install bucket-cli
24
+ ~~~
18
25
 
19
26
  ## Usage
20
27
 
21
- TODO: Write usage instructions here
28
+ ### Setup
29
+ After the installation, you can run
30
+
31
+ ~~~ sh
32
+ $ bucket setup
33
+ ~~~
34
+
35
+ to start the configuration.
36
+
37
+ You need to add your BitBucket username and password (for now it's saved in *plaintext* in `~/.bucket` with a permission bit of `0600`, in the future this will change for oauth authorization).
38
+
39
+ ### Init repository
40
+ You can initialize a new repository (as in doing `git init`), and automagically creating the repository on BitBucket and adding the remote to `origin`.
41
+
42
+ ~~~ sh
43
+ $ bucket init DIRECTORY
44
+ ~~~
45
+
46
+ This will create a new (private) repository in `DIRECTORY` (can be `.` for current directory), and create a repository named after the destination folder (or as specified in the options) in your BitBucket account.
47
+
48
+ #### Options
49
+
50
+ --name NAME A name for the repository in BitBucket
51
+ --description DESC A description for the repository in BitBucket
52
+ --public Mark the repository as public (private by default)
53
+
54
+ ### Cloning
55
+ You can clone a repository directly from BitBucket with
56
+
57
+ ~~~ sh
58
+ $ bucket clone [USER]/REPOSITORY
59
+ ~~~
60
+
61
+ where `REPOSITORY` is the repository name.
62
+
63
+ If `[USER]` is not supplied, it's assumed you want a repository from your own account. For example, if you want to clone the `bucket-cli` repository from your own account you can just use
64
+
65
+ ~~~ sh
66
+ $ bucket clone bucket-cli
67
+ ~~~
68
+
69
+ but if it's from another account you need to specify it
70
+
71
+ ~~~ sh
72
+ $ bucket clone xaro/bucket-cli
73
+ ~~~
74
+
75
+ ### Listing repositories
76
+ You can list the repositories associated with your account by using
77
+
78
+ ~~~ sh
79
+ $ bucket repos
80
+ ~~~
81
+
82
+ ## TODO
83
+ * Improve error reporting (and exceptions catching)
84
+ * Add more commands
85
+ * Shallow redirect commands to git / mercurial
86
+ * Replace bitbucket api gem (it has too many dependencies and is not complete)
22
87
 
23
88
  ## Contributing
24
89
 
data/Rakefile CHANGED
@@ -5,6 +5,7 @@ task :default => :spec
5
5
 
6
6
  Rake::TestTask.new(:spec) do |t|
7
7
  t.test_files = FileList['spec/**/*_spec.rb']
8
+ t.libs.push 'spec'
8
9
  end
9
10
 
10
11
  desc "Console"
data/bucket.gemspec CHANGED
@@ -18,12 +18,21 @@ Gem::Specification.new do |spec|
18
18
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
20
  spec.require_paths = ["lib"]
21
-
21
+
22
22
  spec.add_dependency "omniauth"
23
23
  spec.add_dependency "thor"
24
24
  spec.add_dependency "bitbucket_rest_api"
25
25
 
26
- spec.add_development_dependency "bundler", "~> 1.3"
26
+ # Git access via Ruby
27
+ spec.add_dependency "git"
28
+
29
+ spec.add_development_dependency "bundler", "~> 1.6"
27
30
  spec.add_development_dependency "rake"
28
31
  spec.add_development_dependency "pry"
32
+
33
+ # Fake the filesystem
34
+ spec.add_development_dependency "fakefs"
35
+
36
+ # Mocks
37
+ spec.add_development_dependency "rr"
29
38
  end
data/lib/bucket/cli.rb CHANGED
@@ -1,14 +1,19 @@
1
1
  require "thor"
2
2
  require "io/console"
3
3
  require "yaml"
4
+ require "git"
4
5
  require_relative "../bucket"
5
6
 
6
7
  module Bucket
7
8
  class CLI < Thor
9
+ include Thor::Actions
10
+
11
+ CONFIG_FILE_PATH = "#{Dir.home}/.bucket"
12
+
8
13
  def initialize(*args)
9
14
  super
10
15
 
11
- @client = Bucket::Client.new load_config
16
+ @client = Bucket::Client.new(load_config)
12
17
  end
13
18
 
14
19
  desc "setup", "Setup your BitBucket credentials"
@@ -25,38 +30,46 @@ module Bucket
25
30
  end
26
31
  end
27
32
 
28
- desc "clone [USER] [NAME]", "Clone repository USER/NAME from bitbucket."
29
- def clone(user, name)
30
- `git clone #{@client.repo_url(user, name)}`
33
+ desc "clone [USER]/REPOSITORY", "Clone repository REPOSITORY from bitbucket.\nIf [USER] is ommited, it is assumed that it's your BitBucket user."
34
+ def clone(name)
35
+ begin
36
+ repository = Git::Base.clone(@client.repo_url(name), name)
37
+ say("Repository cloned to #{repository.dir}")
38
+ rescue Git::GitExecuteError => e
39
+ say("Could not clone repository")
40
+ say(e.message)
41
+ end
31
42
  end
32
43
 
33
- desc "init [directory]", "Create a new repository locally and on BitBucket."
34
- option :name
35
- option :description
36
- option :public, type: :boolean, default: false
44
+ desc "init DIRECTORY", "Create a new repository locally and on BitBucket."
45
+ option :name, desc: "The name of the repository. If not specified, the current folder will be used."
46
+ option :description, desc: "A description for the repository."
47
+ option :public, desc: "Sets if the repository is public or private.", type: :boolean, default: false
37
48
  def init(directory)
38
49
  expanded_dir = File.expand_path(directory)
39
- `git init #{expanded_dir}`
40
-
41
- repo = @client.create_repo(options[:name] || File.basename(expanded_dir), options)
42
- `git remote add origin #{@client.repo_url(repo[:owner], repo[:slug])}`
50
+ repository = Git::Base.init(expanded_dir)
43
51
 
44
- say("Repository #{@client.repo_full_name(repo)} created.")
52
+ # Create the BitBucket repository and add it to the local remotes
53
+ remote_repository = @client.create_repo(options[:name] || File.basename(expanded_dir), options)
54
+ remote_url = @client.repo_url("#{remote_repository[:owner]}/#{remote_repository[:slug]}")
55
+ repository.add_remote("BitBucket", remote_url)
56
+
57
+ say("Repository #{@client.repo_full_name(remote_repository)} with remote #{remote_url} created.")
45
58
  end
46
59
 
47
60
  private
48
61
  def load_config
49
- YAML.load_file("#{Dir.home}/.bucket")
62
+ YAML.load_file(CONFIG_FILE_PATH)
50
63
  rescue
51
64
  generate_config
52
65
  end
53
66
 
54
67
  def generate_config
55
- save_config ask_credentials
68
+ save_config(ask_credentials)
56
69
  end
57
70
 
58
71
  def save_config(credentials)
59
- File.open "#{Dir.home}/.bucket", 'w' do |f|
72
+ File.open CONFIG_FILE_PATH, 'w', 0600 do |f|
60
73
  YAML.dump(credentials , f)
61
74
  end
62
75
 
@@ -64,10 +77,12 @@ module Bucket
64
77
  end
65
78
 
66
79
  def ask_credentials
67
- username = @shell.ask("Username:")
68
- @shell.say("Password: ")
69
- password = $stdin.noecho(&:gets).strip
70
- @shell.say("")
80
+ username = ask("Username:")
81
+
82
+ # Avoid echoing the password
83
+ password = ask("Password:", echo: false)
84
+
85
+ say("\nWARNING: For now, the password is saved IN PLAIN TEXT in the ~/.bucket file.")
71
86
 
72
87
  { "username" => username, "password" => password }
73
88
  end
data/lib/bucket/client.rb CHANGED
@@ -3,17 +3,33 @@ module Bucket
3
3
  GIT_URL = "git@bitbucket.org"
4
4
 
5
5
  def initialize(credentials)
6
- @connection = BitBucket.new basic_auth: "#{credentials["username"]}:#{credentials["password"]}"
6
+ @connection = BitBucket.new(basic_auth: "#{credentials["username"]}:#{credentials["password"]}")
7
+ @user = credentials["username"]
7
8
  end
8
9
 
9
10
  def repos_list
10
11
  @connection.repos.list
11
12
  end
12
13
 
13
- def repo_url(user, name)
14
- "#{GIT_URL}:#{user}/#{name}.git"
14
+ # Full url for the given repository
15
+ # The repository name must be of the style [USER]/[REPOSITORY] or
16
+ # [REPOSITORY] in which case the name of the current user
17
+ # will be used as owner
18
+ def repo_url(name)
19
+ split_name = name.split "/"
20
+
21
+ if split_name.size == 1
22
+ user = @user
23
+ slug = split_name[0]
24
+ else
25
+ user = split_name[0]
26
+ slug = split_name[1]
27
+ end
28
+
29
+ "#{GIT_URL}:#{user}/#{slug}.git"
15
30
  end
16
31
 
32
+ # A repository full name is of the style of [USER]/[REPOSITORY]
17
33
  def repo_full_name(repo)
18
34
  "#{repo[:owner]}/#{repo[:slug]}"
19
35
  end
@@ -24,6 +40,5 @@ module Bucket
24
40
 
25
41
  @connection.repos.create(options.merge(name: name))
26
42
  end
27
-
28
43
  end
29
44
  end
@@ -1,3 +1,3 @@
1
1
  module Bucket
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+ require 'fakefs/safe'
3
+
4
+ describe Bucket::CLI do
5
+ subject { Bucket::CLI.new }
6
+
7
+ # Use a fake filesystem and clear it after each test
8
+ before do
9
+ mock_credentials
10
+ FakeFS.activate!
11
+
12
+ # Create a fake user's home (in reality this folder will exist)
13
+ FileUtils.mkdir_p(Dir.home)
14
+ end
15
+ after do
16
+ FakeFS.deactivate!
17
+ FakeFS::FileSystem.clear
18
+ end
19
+
20
+ it "saves the user and password to the configuration file" do
21
+ # The setup is run when initializing the CLI
22
+ out = capture_io { subject }
23
+
24
+ config = YAML.load_file(Bucket::CLI::CONFIG_FILE_PATH)
25
+ config.must_equal({ "username" => "user", "password" => "password" })
26
+ end
27
+
28
+ it "replaces the user and password when calling setup" do
29
+ # Run the setup when initializing (and ignore output)
30
+ capture_io { subject }
31
+
32
+ # Run the setup again with other credentials
33
+ mock_credentials("other_user", "other_password")
34
+ capture_io { subject.setup }
35
+
36
+ config = YAML.load_file(Bucket::CLI::CONFIG_FILE_PATH)
37
+ config.must_equal({ "username" => "other_user", "password" => "other_password" })
38
+ end
39
+
40
+ it "displays a list of the user's repositories" do
41
+ any_instance_of(Bucket::Client) do |client|
42
+ mock(client).repos_list do
43
+ [
44
+ { owner: "user", slug: "repository" },
45
+ { owner: "other_user", slug: "other_repository" }
46
+ ]
47
+ end
48
+ end
49
+
50
+ out = capture_io { subject.repos }.join('')
51
+ out.must_match(/user\/repository/)
52
+ out.must_match(/other_user\/other_repository/)
53
+ end
54
+ end
55
+
56
+ def mock_credentials(username = "user", password = "password")
57
+ any_instance_of(Bucket::CLI) do |cli|
58
+ mock(cli).ask("Username:") { username }
59
+ mock(cli).ask("Password:", anything) { password }
60
+ end
61
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bucket::Client do
4
+ subject { Bucket::Client.new({ "username" => "user", "password" => "password" }) }
5
+
6
+ it "returns the correct repository url when using USER/REPOSITORY syntax" do
7
+ subject.repo_url("other_user/repository").must_equal("git@bitbucket.org:other_user/repository.git")
8
+ end
9
+
10
+ it "returns the correct repository url when using REPOSITORY syntax" do
11
+ subject.repo_url("repository").must_equal("git@bitbucket.org:user/repository.git")
12
+ end
13
+
14
+ it "returns the full name of a repository from a hash containing the repository information" do
15
+ repo_hash = { owner: "user", slug: "repository" }
16
+
17
+ subject.repo_full_name(repo_hash).must_equal("user/repository")
18
+ end
19
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,28 @@
1
1
  require "minitest/autorun"
2
2
  require "minitest/pride"
3
3
 
4
- require_relative "../lib/bucket"
4
+ require 'rr'
5
+
6
+ require_relative "../lib/bucket"
7
+ require_relative "../lib/bucket/cli"
8
+
9
+ # Thor complains when a task does not have a description, we
10
+ # need to silence it when mocking commands
11
+ # https://github.com/jondot/logbook/blob/master/spec/spec_helper.rb
12
+ require 'thor'
13
+ class Thor
14
+ class << self
15
+ def create_command(meth) #:nodoc:
16
+ if @usage && @desc
17
+ base_class = @hide ? Thor::HiddenTask : Thor::Task
18
+ tasks[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
19
+ @usage, @desc, @long_desc, @method_options, @hide = nil
20
+ true
21
+ elsif self.all_tasks[meth] || meth == "method_missing"
22
+ true
23
+ else
24
+ false
25
+ end
26
+ end
27
+ end
28
+ end
metadata CHANGED
@@ -1,97 +1,139 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bucket-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roberto Poo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-01 00:00:00.000000000 Z
11
+ date: 2014-08-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: omniauth
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: thor
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bitbucket_rest_api
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: git
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
53
67
  - !ruby/object:Gem::Version
54
68
  version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: bundler
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
- - - ~>
73
+ - - "~>"
60
74
  - !ruby/object:Gem::Version
61
- version: '1.3'
75
+ version: '1.6'
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
- - - ~>
80
+ - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: '1.3'
82
+ version: '1.6'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rake
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
- - - '>='
87
+ - - ">="
74
88
  - !ruby/object:Gem::Version
75
89
  version: '0'
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
- - - '>='
94
+ - - ">="
81
95
  - !ruby/object:Gem::Version
82
96
  version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: pry
85
99
  requirement: !ruby/object:Gem::Requirement
86
100
  requirements:
87
- - - '>='
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: fakefs
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rr
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
88
130
  - !ruby/object:Gem::Version
89
131
  version: '0'
90
132
  type: :development
91
133
  prerelease: false
92
134
  version_requirements: !ruby/object:Gem::Requirement
93
135
  requirements:
94
- - - '>='
136
+ - - ">="
95
137
  - !ruby/object:Gem::Version
96
138
  version: '0'
97
139
  description: CLI for BitBucket
@@ -102,7 +144,7 @@ executables:
102
144
  extensions: []
103
145
  extra_rdoc_files: []
104
146
  files:
105
- - .gitignore
147
+ - ".gitignore"
106
148
  - Gemfile
107
149
  - LICENSE.txt
108
150
  - README.md
@@ -113,7 +155,8 @@ files:
113
155
  - lib/bucket/cli.rb
114
156
  - lib/bucket/client.rb
115
157
  - lib/bucket/version.rb
116
- - spec/bucket_spec.rb
158
+ - spec/bucket/cli_spec.rb
159
+ - spec/bucket/client_spec.rb
117
160
  - spec/spec_helper.rb
118
161
  homepage: https://github.com/xaro/bucket
119
162
  licenses:
@@ -125,22 +168,23 @@ require_paths:
125
168
  - lib
126
169
  required_ruby_version: !ruby/object:Gem::Requirement
127
170
  requirements:
128
- - - '>='
171
+ - - ">="
129
172
  - !ruby/object:Gem::Version
130
173
  version: '0'
131
174
  required_rubygems_version: !ruby/object:Gem::Requirement
132
175
  requirements:
133
- - - '>='
176
+ - - ">="
134
177
  - !ruby/object:Gem::Version
135
178
  version: '0'
136
179
  requirements: []
137
180
  rubyforge_project:
138
- rubygems_version: 2.0.3
181
+ rubygems_version: 2.2.2
139
182
  signing_key:
140
183
  specification_version: 4
141
184
  summary: Easily clone and create repositories in BitBucket from the command line.
142
185
  Init and link the local repository with a new BitBucket one in one command.
143
186
  test_files:
144
- - spec/bucket_spec.rb
187
+ - spec/bucket/cli_spec.rb
188
+ - spec/bucket/client_spec.rb
145
189
  - spec/spec_helper.rb
146
190
  has_rdoc:
data/spec/bucket_spec.rb DELETED
@@ -1,3 +0,0 @@
1
- describe "Bucket" do
2
- subject { Bucket }
3
- end