gitti 0.1.0 → 0.4.1

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: 47d89819b39043972c9b7eb001c6295640482f6f
4
- data.tar.gz: 9ab6759b243dd50d6bf6cc84f598f013a896e838
3
+ metadata.gz: 22e1840beecff16feb5247fa52e7c6c5ce7deaa3
4
+ data.tar.gz: 70495a4374a990460a505c3b927f3501b91c74a5
5
5
  SHA512:
6
- metadata.gz: 6f345ee2b66cd374cd1e7969235ed65324a1c34e814f40126e7f8be9ff7eab29dc3c484fc5eb95cc4aaf88ab4989b48f4cee8f68f28fb623ff1de9a5f5660d7e
7
- data.tar.gz: c8657d76b2919817ce5f90fa34b31d4a595ee8ac3db39d6398ee5c4d700e6ef993a7adc33001f489267da781446e7c62824e0f946977ce041ffb5126377ed507
6
+ metadata.gz: 196886378c5879ff3ac790e25e017cd0c48af5d8c15f2073f99b2d25caca2ec878e81a073da1ca2cbf4f2fd40e76317b7e01a2a7fb4268d325db4a36f1e58bad
7
+ data.tar.gz: b15e3d0bbcdfa562ee4ac600fd8b2acd6d72d52c331e124defe04d12cb5e944844f28ba042c3390f7de8cfa5aabea702f2cbce6ed4baacd9c058d60a28662281
File without changes
@@ -1,7 +1,13 @@
1
- HISTORY.md
1
+ CHANGELOG.md
2
2
  Manifest.txt
3
3
  README.md
4
4
  Rakefile
5
5
  lib/gitti.rb
6
- lib/gitti/lib.rb
6
+ lib/gitti/base.rb
7
+ lib/gitti/git.rb
8
+ lib/gitti/mirror.rb
9
+ lib/gitti/project.rb
10
+ lib/gitti/reposet.rb
7
11
  lib/gitti/version.rb
12
+ test/helper.rb
13
+ test/test_base.rb
data/README.md CHANGED
@@ -1,16 +1,162 @@
1
1
  # gitti
2
2
 
3
- gitti gem - (yet) another (lite) git command line wrapper / library
3
+ gitti gem - (yet) another (lite) git command line helper / wrapper
4
4
 
5
- * home :: [github.com/rubylibs/gitti](https://github.com/rubylibs/gitti)
6
- * bugs :: [github.com/rubylibs/gitti/issues](https://github.com/rubylibs/gitti/issues)
5
+ * home :: [github.com/rubycoco/gitti](https://github.com/rubycoco/gitti)
6
+ * bugs :: [github.com/rubycoco/gitti/issues](https://github.com/rubycoco/gitti/issues)
7
7
  * gem :: [rubygems.org/gems/gitti](https://rubygems.org/gems/gitti)
8
8
  * rdoc :: [rubydoc.info/gems/gitti](http://rubydoc.info/gems/gitti)
9
9
 
10
10
 
11
+
11
12
  ## Usage
12
13
 
13
- TBD
14
+ `Git` • `GitProject` • `GitMirror`
15
+
16
+
17
+ ### `Git` Class
18
+
19
+ Use the `Git` class for "low-level / to the metal" git commands
20
+ that run in your current working directory.
21
+ Example:
22
+
23
+ ``` ruby
24
+
25
+ ###############
26
+ ## "setup" starter git commands
27
+
28
+ Git.clone( "https://github.com/rubycoco/gitti.git" )
29
+ Git.clone( "https://github.com/rubycoco/gitti.git", "gitti-clone" )
30
+ # -or- -- if you have write / commit access use ssh
31
+ Git.clone( "git@github.com:rubycoco/gitti.git" )
32
+ Git.clone( "git@github.com:rubycoco/gitti.git", "gitti-clone" )
33
+
34
+ Git.mirror( "https://github.com/rubycoco/gitti.git" ) ## same as git clone --mirror
35
+
36
+ #################
37
+ ## standard git commands
38
+
39
+ Git.version ## same as git --version
40
+ Git.status
41
+ Git.status( short: true ) ## same as Git.changes
42
+ Git.changes ## same as git status --short
43
+
44
+ #####################
45
+ ## status helpers
46
+
47
+ Git.clean?
48
+ Git.changes?
49
+ Git.dirty? ## alias for changes?
50
+
51
+ #######
52
+ ## more (major) git commands
53
+
54
+ Git.fetch
55
+ Git.pull
56
+ Git.fast_forward ## same as git pull --ff-only
57
+ Git.ff ## alias for fast_forward
58
+ Git.push
59
+ Git.add( "pathspec" )
60
+ Git.add_all ## same as git --all
61
+ Git.commit( "message" )
62
+
63
+ Git.files ## same as git ls-tree --full-tree --name-only -r HEAD
64
+
65
+ Git.check ## same as git fsck
66
+ Git.fsck ## alias for check
67
+ Git.checksum ## another alias for check
68
+
69
+ Git.master? ## on master branch
70
+ Git.main? ## on main branch
71
+
72
+ Git.origin ## same as git remote show origin
73
+ Git.upstream ## same as git remote show upstream
74
+ Git.origin?
75
+ Git.upstream?
76
+
77
+ Git.config( "user.name" ) ## use --get option
78
+ Git.config( "user.name", show_origin: true ) ## add --show-origin flag
79
+ Git.config( "user.name", show_scope: true ) ## add --show-scope flag
80
+
81
+ Git.config( /user/ ) ## use --get-regexp option
82
+ Git.config( /user/, show_origin: true ) ## add --show-origin flag
83
+ Git.config( /user/, show_scope: true ) ## add --show-scope flag
84
+ ```
85
+
86
+
87
+
88
+ ### `GitProject` Class
89
+
90
+ Use the `GitProject` class for existing git repo(sitories)
91
+ with workspace. Example:
92
+
93
+ ``` ruby
94
+ GitProject.open( "rubycoco/gitti" ) do |proj|
95
+ proj.status
96
+ proj.status( short: true )
97
+ proj.changes
98
+ proj.clean?
99
+ proj.changes?
100
+ proj.dirty?
101
+
102
+ proj.fetch
103
+ proj.pull
104
+ proj.fast_forward
105
+ proj.ff
106
+
107
+ proj.push
108
+
109
+ proj.add( "pathspec" )
110
+ proj.add_all
111
+ proj.commit( "message" )
112
+
113
+ proj.files
114
+
115
+ proj.master?
116
+ proj.main?
117
+
118
+ proj.origin
119
+ proj.upstream
120
+ proj.origin?
121
+ proj.upstream?
122
+ end
123
+ ```
124
+
125
+
126
+ ### `GitMirror` Class
127
+
128
+ Use the `GitMirror` class for existing mirrored (bare) git repo(sitories)
129
+ without workspace. Example:
130
+
131
+ ``` ruby
132
+ GitMirror.open( "rubycoco/gitti.git" ) do |mirror|
133
+ mirror.update # sames as git remote update
134
+ end
135
+ ```
136
+
137
+
138
+
139
+ That's it for now.
140
+
141
+
142
+
143
+ ## Real World Usage
144
+
145
+ The [`monos`](https://github.com/rubycoco/monos) gem incl. some monorepo / mono source tree tools and (startup) scripts
146
+ that let you run git commands on multiple repos.
147
+
148
+
149
+
150
+ ## Installation
151
+
152
+ Use
153
+
154
+ gem install gitti
155
+
156
+ or add to your Gemfile
157
+
158
+ gem 'gitti'
159
+
14
160
 
15
161
 
16
162
  ## License
data/Rakefile CHANGED
@@ -3,28 +3,26 @@ require './lib/gitti/version.rb'
3
3
 
4
4
  Hoe.spec 'gitti' do
5
5
 
6
- self.version = Gitti::VERSION
6
+ self.version = GittiCore::VERSION
7
7
 
8
- self.summary = 'gitti - (yet) another (lite) git command line wrapper / library'
8
+ self.summary = 'gitti - (yet) another (lite) git command line helper / wrapper'
9
9
  self.description = summary
10
10
 
11
- self.urls = ['https://github.com/rubylibs/gitti']
11
+ self.urls = { home: 'https://github.com/rubycoco/gitti' }
12
12
 
13
13
  self.author = 'Gerald Bauer'
14
14
  self.email = 'ruby-talk@ruby-lang.org'
15
15
 
16
16
  # switch extension to .markdown for gihub formatting
17
17
  self.readme_file = 'README.md'
18
- self.history_file = 'HISTORY.md'
18
+ self.history_file = 'CHANGELOG.md'
19
19
 
20
- self.extra_deps = [
21
- ['logutils' ],
22
- ]
20
+ self.extra_deps = []
23
21
 
24
22
  self.licenses = ['Public Domain']
25
23
 
26
24
  self.spec_extras = {
27
- required_ruby_version: '>= 1.9.2'
25
+ required_ruby_version: '>= 2.2.2'
28
26
  }
29
27
 
30
28
  end
@@ -1,21 +1,7 @@
1
- # encoding: utf-8
1
+ require_relative 'gitti/base'
2
2
 
3
- require 'net/http'
4
- require "net/https"
5
- require 'uri'
3
+ ## note: auto include Gitti; for "modular" version use ("Sinatra-style")
4
+ ## require "gitti/base"
6
5
 
7
- require 'pp'
8
- require 'json'
9
- require 'yaml'
6
+ include Gitti
10
7
 
11
-
12
- # 3rd party gems/libs
13
- require 'logutils'
14
-
15
- # our own code
16
- require 'gitti/version' # note: let version always go first
17
- require 'gitti/lib'
18
-
19
-
20
- # say hello
21
- puts Gitti.banner if defined?($RUBYLIBS_DEBUG)
@@ -0,0 +1,57 @@
1
+ require 'pp'
2
+ require 'time'
3
+ require 'date' ## e.g. Date.today etc.
4
+ require 'yaml'
5
+ require 'json'
6
+ require 'uri'
7
+ require 'net/http'
8
+ require "net/https"
9
+ require 'open3'
10
+ require 'fileutils' ## e.g. FileUtils.mkdir_p etc.
11
+
12
+
13
+
14
+ # our own code
15
+ require 'gitti/version' # note: let version always go first
16
+ require 'gitti/git'
17
+ require 'gitti/project'
18
+ require 'gitti/mirror'
19
+ require 'gitti/reposet'
20
+
21
+
22
+
23
+ module Gitti
24
+ ## todo: change to GitHubRepoRef or GitHubProject
25
+ ## or Git::GitHub or Git::Source::GitHub or such - why? why not?
26
+ class GitHubRepo
27
+ attr_reader :owner, :name
28
+
29
+ def initialize( owner, name )
30
+ @owner = owner ## use/rename to login or something - why? why not??
31
+ @name = name # e.g. "rubylibs/webservice"
32
+ end
33
+
34
+
35
+ def ssh_clone_url
36
+ ## check: use https: as default? for github - http:// still supported? or redirected?
37
+ ## "http://github.com/#{@owner}/#{@name}"
38
+ "git@github.com:#{@owner}/#{@name}.git"
39
+ end
40
+
41
+ def http_clone_url ## use clone_url( http: true ) -- why? why not?
42
+ ## note: https is default for github - http:// gets redirected to https://
43
+ "http://github.com/#{@owner}/#{@name}"
44
+ end
45
+
46
+ def https_clone_url
47
+ "https://github.com/#{@owner}/#{@name}"
48
+ end
49
+
50
+
51
+ end ## class GitHubRepo
52
+ end ## module Gitti
53
+
54
+
55
+
56
+ # say hello
57
+ puts GittiCore.banner ## if defined?( $RUBYCOCO_DEBUG )
@@ -0,0 +1,315 @@
1
+ module Gitti
2
+
3
+ ## raised by Git::Shell.run -- check if top-level ShellError alread exists?
4
+ ## use ShellError or RunError - why? why not?
5
+ ## and make Git::Shell top-level e.g. Shell - why? why not?
6
+ class GitError < StandardError
7
+ end
8
+
9
+
10
+ class Git ## make Git a module - why? why not?
11
+
12
+ ###
13
+ ## todo/fix: change opts=nil to *args or such - why? why not?
14
+
15
+
16
+ ###############
17
+ ## "setup" starter git commands
18
+
19
+ def self.clone( repo, name=nil, depth: nil )
20
+ cmd = "git clone #{repo}"
21
+ cmd << " #{name}" unless name.nil? || name.empty?
22
+ cmd << " --depth #{depth}" unless depth.nil?
23
+ Shell.run( cmd )
24
+ end
25
+
26
+ ###
27
+ ## What's the difference between git clone --mirror and git clone --bare
28
+ ## see https://stackoverflow.com/questions/3959924/whats-the-difference-between-git-clone-mirror-and-git-clone-bare
29
+ ##
30
+ ## The git clone help page has this to say about --mirror:
31
+ ## > Set up a mirror of the remote repository. This implies --bare
32
+ ##
33
+ ## The difference is that when using --mirror, all refs are copied as-is.
34
+ ## This means everything: remote-tracking branches, notes, refs/originals/*
35
+ ## (backups from filter-branch). The cloned repo has it all.
36
+ ## It's also set up so that a remote update will re-fetch everything from the origin
37
+ ## (overwriting the copied refs). The idea is really to mirror the repository,
38
+ ## to have a total copy, so that you could for example host your central repo
39
+ ## in multiple places, or back it up. Think of just straight-up copying the repo,
40
+ ## except in a much more elegant git way.
41
+ ##
42
+ ## The new documentation pretty much says all this:
43
+ ## see https://git-scm.com/docs/git-clone
44
+ ##
45
+ ## --mirror
46
+ ## Set up a mirror of the source repository. This implies --bare.
47
+ ## Compared to --bare, --mirror not only maps local branches of the source
48
+ ## to local branches of the target, it maps all refs
49
+ ## (including remote-tracking branches, notes etc.) and sets up a refspec configuration
50
+ ## such that all these refs are overwritten by a git remote update
51
+ ## in the target repository.
52
+ ##
53
+ ## More Articles / Resources:
54
+ ## https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/duplicating-a-repository
55
+
56
+
57
+ ## add -n (--no-checkout) -- needed - why? why not?
58
+ ## add --no-hardlinks -- needed/recommended - why? why not?
59
+
60
+ def self.mirror( repo )
61
+ cmd = "git clone --mirror #{repo}"
62
+ Shell.run( cmd )
63
+ end
64
+
65
+
66
+ #################
67
+ ## standard git commands
68
+
69
+ def self.version
70
+ cmd = 'git --version'
71
+ Shell.run( cmd )
72
+ end
73
+
74
+ def self.status( short: false )
75
+ cmd = 'git status'
76
+ cmd << " --short" if short
77
+ Shell.run( cmd )
78
+ end
79
+
80
+ def self.changes ## same as git status --short - keep shortcut / alias - why? why not?
81
+ ## returns changed files - one per line or empty if no changes
82
+ cmd = 'git status --short'
83
+ Shell.run( cmd )
84
+ end
85
+
86
+ #####################
87
+ ## status helpers
88
+
89
+ ## git status --short returns empty stdout/list
90
+ def self.clean?() changes.empty?; end
91
+
92
+ def self.changes?() clean? == false; end ## reverse of clean?
93
+ class << self
94
+ alias_method :dirty?, :changes? ## add alias
95
+ end
96
+
97
+
98
+ #######
99
+ ## more (major) git commands
100
+
101
+ def self.fetch
102
+ cmd = 'git fetch'
103
+ Shell.run( cmd )
104
+ end
105
+
106
+ def self.pull
107
+ cmd = 'git pull'
108
+ Shell.run( cmd )
109
+ end
110
+
111
+ def self.fast_forward
112
+ cmd = 'git pull --ff-only'
113
+ Shell.run( cmd )
114
+ end
115
+ class << self
116
+ alias_method :ff, :fast_forward ## add alias
117
+ end
118
+
119
+
120
+ def self.push
121
+ cmd = 'git push'
122
+ Shell.run( cmd )
123
+ end
124
+
125
+ def self.add( *pathspecs ) ## e.g. git add . or git add *.rb or such
126
+ cmd = 'git add'
127
+ pathspecs = ['.'] if pathspecs.size == 0
128
+ cmd << " #{pathspecs.join('')}"
129
+ Shell.run( cmd )
130
+ end
131
+
132
+ def self.add_all
133
+ cmd = 'git add --all'
134
+ Shell.run( cmd )
135
+ end
136
+
137
+ def self.commit( message )
138
+ ### todo/check: make message.nil? an ArgumentError - why? why not?
139
+ ### if message.nil? || message.empty?
140
+
141
+ cmd = 'git commit'
142
+ cmd << %Q{ -m "#{message}"}
143
+
144
+ Shell.run( cmd )
145
+ end
146
+
147
+
148
+ #############
149
+ # change git ls-files to git ls-tree ... - why? why not?
150
+ ## - note: git ls-files will include stages files too
151
+ # not only committed ones!!!
152
+ #
153
+ # git ls-tree --full-tree --name-only -r HEAD
154
+ # 1) --full-tree makes the command run as if you were in the repo's root directory.
155
+ # 2) -r recurses into subdirectories. Combined with --full-tree, this gives you all committed, tracked files.
156
+ # 3) --name-only removes SHA / permission info for when you just want the file paths.
157
+ # 4) HEAD specifies which branch you want the list of tracked, committed files for.
158
+ # You could change this to master or any other branch name, but HEAD is the commit you have checked out right now.
159
+ #
160
+ # see https://stackoverflow.com/questions/15606955/how-can-i-make-git-show-a-list-of-the-files-that-are-being-tracked
161
+ #
162
+ # was:
163
+
164
+ def self.files ## was: e.g. git ls-files . or git ls-files *.rb or such
165
+ ### todo/check: include --full-tree - why? why not?
166
+ ## will ALWAYS list all files NOT depending on (current) working directory
167
+
168
+ cmd = 'git ls-tree --full-tree --name-only -r HEAD' # was: 'git ls-files'
169
+ Shell.run( cmd )
170
+ end
171
+ ## add list_files or ls_files alias - why? why not?
172
+
173
+
174
+ ########
175
+ ## query git configuration helpers
176
+ def self.config( prop,
177
+ show_origin: false,
178
+ show_scope: false ) ## find a better name e.g. config_get? why? why not?
179
+ cmd = "git config"
180
+ cmd << " --show-origin" if show_origin
181
+ cmd << " --show-scope" if show_scope
182
+
183
+ if prop.is_a?( Regexp )
184
+ ## note: use Regexp#source
185
+ ## Returns the original string of the pattern.
186
+ ## e.g. /ab+c/ix.source #=> "ab+c"
187
+ ## Note that escape sequences are retained as is.
188
+ ## /\x20\+/.source #=> "\\x20\\+"
189
+ cmd << " --get-regexp #{prop.source}"
190
+ else ## assume string
191
+ cmd << " --get #{prop}"
192
+ end
193
+
194
+ Shell.run( cmd )
195
+ end
196
+
197
+
198
+ def self.branch
199
+ cmd = 'git branch'
200
+ Shell.run( cmd )
201
+ end
202
+
203
+ def self.master?
204
+ output = branch ## check for '* master'
205
+ output.split( /\r?\n/ ).include?( '* master' )
206
+ end
207
+
208
+ def self.main?
209
+ output = branch ## check for '* main'
210
+ output.split( /\r?\n/ ).include?('* main')
211
+ end
212
+
213
+ ## git remote update will update all of your branches
214
+ ## set to track remote ones, but not merge any changes in.
215
+ ##
216
+ ## git fetch --all didn't exist at one time, so git remote update what more useful.
217
+ ## Now that --all has been added to git fetch, git remote update is not really necessary.
218
+ ##
219
+ ## Differences between git remote update and fetch?
220
+ ## Is git remote update the equivalent of git fetch?
221
+ ## see https://stackoverflow.com/questions/1856499/differences-between-git-remote-update-and-fetch/17512004#17512004
222
+ ##
223
+ ## git fetch learned --all and --multiple options,
224
+ ## to run fetch from many repositories,
225
+ ## and --prune option to remove remote tracking branches that went stale.
226
+ ## These make git remote update and git remote prune less necessary
227
+ ## (there is no plan to remove remote update nor remote prune, though).
228
+ def self.update
229
+ cmd = 'git remote update'
230
+ Shell.run( cmd )
231
+ end
232
+
233
+
234
+ def self.origin ## e.g. git remote show origin
235
+ cmd = "git remote show origin"
236
+ Shell.run( cmd )
237
+ end
238
+
239
+ def self.upstream ## e.g. git remote show origin
240
+ cmd = "git remote show upstream"
241
+ Shell.run( cmd )
242
+ end
243
+
244
+ def self.remote
245
+ cmd = "git remote"
246
+ Shell.run( cmd )
247
+ end
248
+
249
+ def self.origin?
250
+ output = remote ## check for 'origin'
251
+ output.split( /\r?\n/ ).include?( 'origin' )
252
+ end
253
+
254
+ def self.upstream?
255
+ output = remote ## check for 'upstream'
256
+ output.split( /\r?\n/ ).include?( 'upstream' )
257
+ end
258
+
259
+
260
+
261
+ def self.check ## e.g. git fsck - check/validate hash of objects
262
+ cmd = "git fsck"
263
+ Shell.run( cmd )
264
+ end
265
+ class << self
266
+ alias_method :fsck, :check ## add alias
267
+ alias_method :checksum, :check
268
+ end
269
+
270
+
271
+
272
+ ###
273
+ # use nested class for "base" for running commands - why? why not?
274
+ class Shell
275
+ def self.run( cmd )
276
+ print "cmd exec >#{cmd}<..."
277
+ stdout, stderr, status = Open3.capture3( cmd )
278
+
279
+ if status.success?
280
+ print " OK"
281
+ print "\n"
282
+ else
283
+ print " FAIL (#{status.exitstatus})"
284
+ print "\n"
285
+ end
286
+
287
+ unless stdout.empty?
288
+ puts stdout
289
+ end
290
+
291
+ unless stderr.empty?
292
+ ## todo/check: or use >2: or &2: or such
293
+ ## stderr output not always an error (that is, exit status might be 0)
294
+ puts "2>"
295
+ puts stderr
296
+ end
297
+
298
+ if status.success?
299
+ stdout # return stdout string
300
+ else
301
+ puts "!! ERROR: cmd exec >#{cmd}< failed with exit status #{status.exitstatus}:"
302
+ puts stderr
303
+
304
+ ### todo/fix: do NOT use GitError here!!! make it more "general"
305
+ ### use a Git::Shell.run() wrapper or such - why? why not?
306
+ ## or use a Shell.git() or Shell.git_run() ???
307
+ ## or pass in error class - why? why not?
308
+ raise GitError, "cmd exec >#{cmd}< failed with exit status #{status.exitstatus}<: #{stderr}"
309
+ end
310
+ end
311
+ end # class Git::Shell
312
+
313
+ end # class Git
314
+
315
+ end # module Gitti
@@ -0,0 +1,33 @@
1
+ module Gitti
2
+
3
+ class GitMirror
4
+ def self.open( path, &blk )
5
+ new( path ).open( &blk )
6
+ end
7
+
8
+ def self.update( path ) ### all-in-one convenience shortcut
9
+ new( path).open { |mirror| mirror.update }
10
+ end
11
+
12
+
13
+
14
+ def initialize( path )
15
+ raise ArgumentError, "dir >#{path}< not found; dir MUST already exist for GitMirror class - sorry" unless Dir.exist?( path )
16
+ ## todo/check: check for more dirs and files e.g.
17
+ ## /info,/objects,/refs, /hooks, HEAD, config, description -- why? why not?
18
+ raise ArgumentError, "dir >#{path}/objects< not found; dir MUST already be initialized with git for GitMirror class - sorry" unless Dir.exist?( "#{path}/objects" )
19
+ @path = path
20
+ end
21
+
22
+
23
+ def open( &blk )
24
+ Dir.chdir( @path ) do
25
+ blk.call( self )
26
+ end
27
+ end
28
+
29
+ def update() Git.update; end
30
+
31
+ end # class GitMirror
32
+ end # module Gitti
33
+
@@ -0,0 +1,61 @@
1
+ module Gitti
2
+
3
+ class GitProject
4
+ def self.open( path, &blk )
5
+ new( path ).open( &blk )
6
+ end
7
+
8
+ def initialize( path )
9
+ raise ArgumentError, "dir >#{path}< not found; dir MUST already exist for GitProject class - sorry" unless Dir.exist?( path )
10
+ raise ArgumentError, "dir >#{path}/.git< not found; dir MUST already be initialized with git for GitProject class - sorry" unless Dir.exist?( "#{path}/.git" )
11
+ @path = path
12
+ end
13
+
14
+
15
+ def open( &blk )
16
+ ## puts "Dir.getwd: #{Dir.getwd}"
17
+ Dir.chdir( @path ) do
18
+ blk.call( self )
19
+ end
20
+ ## puts "Dir.getwd: #{Dir.getwd}"
21
+ end
22
+
23
+
24
+ def status( short: false ) Git.status( short: short ); end
25
+ def changes() Git.changes; end
26
+ def clean?() Git.clean?; end
27
+ def changes?() Git.changes?; end
28
+ alias_method :dirty?, :changes?
29
+
30
+
31
+ def fetch() Git.fetch; end
32
+ def pull() Git.pull; end
33
+ def fast_forward() Git.fast_forward; end
34
+ alias_method :ff, :fast_forward
35
+
36
+ def push() Git.push; end
37
+
38
+ def add( *pathspecs ) Git.add( *pathspecs ); end
39
+ def add_all() Git.add_all; end
40
+ def commit( message ) Git.commit( message ); end
41
+
42
+ def files() Git.files; end
43
+
44
+
45
+ ### remote show origin|upstream|etc.
46
+ def remote() Git.remote; end
47
+ def origin() Git.origin; end
48
+ def upstream() Git.upstream; end
49
+ def origin?() Git.origin?; end
50
+ def upstream?() Git.upstream?; end
51
+
52
+ ### branch management
53
+ def branch() Git.branch; end
54
+ def master?() Git.master?; end
55
+ def main?() Git.main?; end
56
+
57
+
58
+ def run( cmd ) Git::Shell.run( cmd ); end
59
+ end # class GitProject
60
+ end # module Gitti
61
+
@@ -0,0 +1,42 @@
1
+
2
+ module Gitti
3
+
4
+
5
+ class GitRepoSet ## todo: rename to Hash/Dict/List/Map or use GitHubRepoSet ??
6
+
7
+ def self.read( path )
8
+ txt = File.open( path, 'r:utf-8') { |f| f.read }
9
+ hash = YAML.load( txt )
10
+ new( hash )
11
+ end
12
+
13
+
14
+ def initialize( hash )
15
+ @hash = hash
16
+ end
17
+
18
+ def size
19
+ ## sum up total number of repos
20
+ @size ||= @hash.reduce(0) {|sum,(_,names)| sum+= names.size; sum }
21
+ end
22
+
23
+ def each
24
+ @hash.each do |org_with_counter,names|
25
+
26
+ ## remove optional number from key e.g.
27
+ ## mrhydescripts (3) => mrhydescripts
28
+ ## footballjs (4) => footballjs
29
+ ## etc.
30
+
31
+ org = org_with_counter.sub( /\([0-9]+\)/, '' ).strip
32
+
33
+ ## puts " -- #{key_with_counter} [#{key}] --"
34
+
35
+ yield( org, names )
36
+ end
37
+ end
38
+
39
+ end ## class GitRepoSet
40
+
41
+ end ## module Gitti
42
+
@@ -1,9 +1,14 @@
1
- # encoding: utf-8
2
1
 
3
- module Gitti
2
+ ### note: use a different module for version (meta) info
3
+ ### that is, GittiCore and NOT Gitti
4
+ ### why? do NOT "pollute" Gitti with MAJOR, MINOR, PATH, and
5
+ ### self.banner, self.root, etc.
6
+
7
+
8
+ module GittiCore ## todo/check: rename GittiBase or GittiMeta or such - why? why not?
4
9
  MAJOR = 0 ## todo: namespace inside version or something - why? why not??
5
- MINOR = 1
6
- PATCH = 0
10
+ MINOR = 4
11
+ PATCH = 1
7
12
  VERSION = [MAJOR,MINOR,PATCH].join('.')
8
13
 
9
14
  def self.version
@@ -17,5 +22,5 @@ module Gitti
17
22
  def self.root
18
23
  "#{File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) )}"
19
24
  end
20
- end # module Gitti
25
+ end # module GittiCore
21
26
 
@@ -0,0 +1,7 @@
1
+ ## minitest setup
2
+ require 'minitest/autorun'
3
+
4
+
5
+ ## our own code
6
+ require 'gitti'
7
+
@@ -0,0 +1,43 @@
1
+ ###
2
+ # to run use
3
+ # ruby -I ./lib -I ./test test/test_base.rb
4
+
5
+ require 'helper'
6
+
7
+ class TestBase < MiniTest::Test
8
+
9
+ def test_branch
10
+ Git.branch
11
+ assert_equal true, Git.master?
12
+ assert_equal false, Git.main?
13
+
14
+ Git.remote
15
+ assert_equal true, Git.origin?
16
+ assert_equal false, Git.upstream?
17
+ end
18
+
19
+
20
+ def test_git_config
21
+ puts "---"
22
+ Git.config( 'user.name' )
23
+ Git.config( 'user.name', show_origin: true )
24
+ ## Git.config( 'user.name', show_scope: true )
25
+
26
+ puts "---"
27
+ Git.config( /user/ ) ## note: pass in regex for regex match/search
28
+ Git.config( /user/, show_origin: true )
29
+ ## Git.config( /user/, show_scope: true )
30
+
31
+ puts "---"
32
+ Git.config( /user\./ ) ## note: pass in regex for regex match/search
33
+
34
+ puts "---"
35
+ ## note: if NOT found Git.config will exit(1) !!!
36
+ ## Git.config( /proxy/, show_origin: true )
37
+ ## Git.config( /http/, show_origin: true )
38
+
39
+ puts "---"
40
+ end
41
+
42
+ end # class TestBase
43
+
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitti
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-17 00:00:00.000000000 Z
11
+ date: 2020-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: logutils
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: rdoc
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -44,31 +30,37 @@ dependencies:
44
30
  requirements:
45
31
  - - "~>"
46
32
  - !ruby/object:Gem::Version
47
- version: '3.14'
33
+ version: '3.16'
48
34
  type: :development
49
35
  prerelease: false
50
36
  version_requirements: !ruby/object:Gem::Requirement
51
37
  requirements:
52
38
  - - "~>"
53
39
  - !ruby/object:Gem::Version
54
- version: '3.14'
55
- description: gitti - (yet) another (lite) git command line wrapper / library
40
+ version: '3.16'
41
+ description: gitti - (yet) another (lite) git command line helper / wrapper
56
42
  email: ruby-talk@ruby-lang.org
57
43
  executables: []
58
44
  extensions: []
59
45
  extra_rdoc_files:
60
- - HISTORY.md
46
+ - CHANGELOG.md
61
47
  - Manifest.txt
62
48
  - README.md
63
49
  files:
64
- - HISTORY.md
50
+ - CHANGELOG.md
65
51
  - Manifest.txt
66
52
  - README.md
67
53
  - Rakefile
68
54
  - lib/gitti.rb
69
- - lib/gitti/lib.rb
55
+ - lib/gitti/base.rb
56
+ - lib/gitti/git.rb
57
+ - lib/gitti/mirror.rb
58
+ - lib/gitti/project.rb
59
+ - lib/gitti/reposet.rb
70
60
  - lib/gitti/version.rb
71
- homepage: https://github.com/rubylibs/gitti
61
+ - test/helper.rb
62
+ - test/test_base.rb
63
+ homepage: https://github.com/rubycoco/gitti
72
64
  licenses:
73
65
  - Public Domain
74
66
  metadata: {}
@@ -82,7 +74,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
82
74
  requirements:
83
75
  - - ">="
84
76
  - !ruby/object:Gem::Version
85
- version: 1.9.2
77
+ version: 2.2.2
86
78
  required_rubygems_version: !ruby/object:Gem::Requirement
87
79
  requirements:
88
80
  - - ">="
@@ -90,8 +82,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
90
82
  version: '0'
91
83
  requirements: []
92
84
  rubyforge_project:
93
- rubygems_version: 2.2.3
85
+ rubygems_version: 2.5.2
94
86
  signing_key:
95
87
  specification_version: 4
96
- summary: gitti - (yet) another (lite) git command line wrapper / library
88
+ summary: gitti - (yet) another (lite) git command line helper / wrapper
97
89
  test_files: []
@@ -1,83 +0,0 @@
1
- # encoding: utf-8
2
-
3
-
4
- module Gitti
5
-
6
- class GitError < StandardError
7
- end
8
-
9
- class GitLib
10
-
11
- def clone( repo, opts={} )
12
- command( "clone #{repo}" )
13
- end
14
-
15
- def mirror( repo, opts={} )
16
- command( "clone --mirror #{repo}" )
17
- end
18
-
19
- def pull( opts={} )
20
- command( "pull" )
21
- end
22
-
23
- def remote_update( opts={} )
24
- command( "remote update" )
25
- end
26
-
27
-
28
- ## todo/fix:
29
- ## add last_exit or something ?? why? why not??
30
-
31
- def command( cmd )
32
- ## note: for now use Kernel#system for calling external git command
33
- ##
34
-
35
- cmdline = "git #{cmd}"
36
- puts " trying >#{cmdline}< in (#{Dir.pwd})..."
37
-
38
- result = nil
39
- result = system( cmdline )
40
-
41
- pp result
42
-
43
- # note: Kernel#system returns
44
- # - true if the command gives zero exit status
45
- # - false for non zero exit status
46
- # - nil if command execution fails
47
- # An error status is available in $?.
48
-
49
- if result.nil?
50
- puts "*** error was #{$?}"
51
- fail "[Kernel.system] command execution failed >#{cmdline}< - #{$?}"
52
- elsif result ## true => zero exit code (OK)
53
- puts 'OK' ## zero exit; assume OK
54
- true ## assume ok
55
- else ## false => non-zero exit code (ERR/NOK)
56
- puts "*** error: non-zero exit - #{$?} !!" ## non-zero exit (e.g. 1,2,3,etc.); assume error
57
-
58
- ## log error for now ???
59
- # File.open( './errors.log', 'a' ) do |f|
60
- # f.write "#{Time.now} -- repo #{@owner}/#{@name} - command execution failed - non-zero exit\n"
61
- # end
62
- raise GitError.new( "command execution failed >#{cmdline}< - non-zero exit (#{$?})" )
63
- end
64
- end # method command
65
- end # class Lib
66
-
67
-
68
- module Git
69
- ## todo/fix: use "shared" singelton lib - why? why not??
70
- def self.clone( repo, opts={} ) GitLib.new.clone( repo, opts ); end
71
- def self.mirror( repo, opts={} ) GitLib.new.mirror( repo, opts ); end
72
-
73
- def self.pull( opts={} ) GitLib.new.pull( opts ); end
74
- def self.remote_update( opts={} ) GitLib.new.remote_update( opts ); end
75
- end # module Git
76
-
77
- end # module Gitti
78
-
79
-
80
- ### convenience top level Git module - check if defined? make optional? why? why not??
81
- ## Git = Gitti::Git
82
-
83
- # for now use include Gitti - why? why not??