bucket-cli 0.0.1 → 0.0.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.
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