gitti 0.2.0 → 0.4.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: 23b94ce3c7dbeb1eb816fc266a520ff277a74a06
4
- data.tar.gz: dff2e5ff8d5d961ae46cc4da765d75a1dfb6f92e
3
+ metadata.gz: 651f519f3b5f3ecf8a13a5125554cac2d69790f6
4
+ data.tar.gz: 7ae7285e8ac625336869c7d4de1d078c11c5ee6d
5
5
  SHA512:
6
- metadata.gz: 740f8d8ca2e1f4e24c97458e3a47e947727613a12649c18d39d7ced494cb73d3c01a5cd64b682ea01563d4eff989d40789cee16441e68cac24b0bd006c6b2f03
7
- data.tar.gz: 1066b7918f78d9ea829e1a53fd9865df7cb3dc9a9a20b5085c2d05a1b1a1ba64b5dbb722f00bb40d104b1cae64aa62370a0171378e409d5818ccaf1fa816a344
6
+ metadata.gz: 7c002bac4f5622a3083b27fa2e29d69736821d14c7b521ecd1a00b06cd62d80cae762e853e96943baa242e77568043a356fecc8c036c8856f18c8eac42facf0c
7
+ data.tar.gz: 694934d8ea8263d11b90f7a14a01f8f59d3d71a695b728ebd82927e66d554cf1e59195199af7c960e930cc9cb4d9ad4c3d93abec28df9fe1aca931304e1f4698
File without changes
@@ -1,8 +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
7
- lib/gitti/support/reposet.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
8
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,24 +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
- ## todo/check: move to its own gem e.g. gitti-support later - why? why not??
20
- require 'gitti/support/reposet'
21
-
22
-
23
- # say hello
24
- 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,316 @@
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"
21
+ cmd << " --depth #{depth}" unless depth.nil?
22
+ cmd << " #{repo}"
23
+ cmd << " #{name}" unless name.nil? || name.empty?
24
+ Shell.run( cmd )
25
+ end
26
+
27
+ ###
28
+ ## What's the difference between git clone --mirror and git clone --bare
29
+ ## see https://stackoverflow.com/questions/3959924/whats-the-difference-between-git-clone-mirror-and-git-clone-bare
30
+ ##
31
+ ## The git clone help page has this to say about --mirror:
32
+ ## > Set up a mirror of the remote repository. This implies --bare
33
+ ##
34
+ ## The difference is that when using --mirror, all refs are copied as-is.
35
+ ## This means everything: remote-tracking branches, notes, refs/originals/*
36
+ ## (backups from filter-branch). The cloned repo has it all.
37
+ ## It's also set up so that a remote update will re-fetch everything from the origin
38
+ ## (overwriting the copied refs). The idea is really to mirror the repository,
39
+ ## to have a total copy, so that you could for example host your central repo
40
+ ## in multiple places, or back it up. Think of just straight-up copying the repo,
41
+ ## except in a much more elegant git way.
42
+ ##
43
+ ## The new documentation pretty much says all this:
44
+ ## see https://git-scm.com/docs/git-clone
45
+ ##
46
+ ## --mirror
47
+ ## Set up a mirror of the source repository. This implies --bare.
48
+ ## Compared to --bare, --mirror not only maps local branches of the source
49
+ ## to local branches of the target, it maps all refs
50
+ ## (including remote-tracking branches, notes etc.) and sets up a refspec configuration
51
+ ## such that all these refs are overwritten by a git remote update
52
+ ## in the target repository.
53
+ ##
54
+ ## More Articles / Resources:
55
+ ## https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/duplicating-a-repository
56
+
57
+
58
+ ## add -n (--no-checkout) -- needed - why? why not?
59
+ ## add --no-hardlinks -- needed/recommended - why? why not?
60
+
61
+ def self.mirror( repo )
62
+ cmd = "git clone --mirror #{repo}"
63
+ Shell.run( cmd )
64
+ end
65
+
66
+
67
+ #################
68
+ ## standard git commands
69
+
70
+ def self.version
71
+ cmd = 'git --version'
72
+ Shell.run( cmd )
73
+ end
74
+
75
+ def self.status( short: false )
76
+ cmd = 'git status'
77
+ cmd << " --short" if short
78
+ Shell.run( cmd )
79
+ end
80
+
81
+ def self.changes ## same as git status --short - keep shortcut / alias - why? why not?
82
+ ## returns changed files - one per line or empty if no changes
83
+ cmd = 'git status --short'
84
+ Shell.run( cmd )
85
+ end
86
+
87
+ #####################
88
+ ## status helpers
89
+
90
+ ## git status --short returns empty stdout/list
91
+ def self.clean?() changes.empty?; end
92
+
93
+ def self.changes?() clean? == false; end ## reverse of clean?
94
+ class << self
95
+ alias_method :dirty?, :changes? ## add alias
96
+ end
97
+
98
+
99
+ #######
100
+ ## more (major) git commands
101
+
102
+ def self.fetch
103
+ cmd = 'git fetch'
104
+ Shell.run( cmd )
105
+ end
106
+
107
+ def self.pull
108
+ cmd = 'git pull'
109
+ Shell.run( cmd )
110
+ end
111
+
112
+ def self.fast_forward
113
+ cmd = 'git pull --ff-only'
114
+ Shell.run( cmd )
115
+ end
116
+ class << self
117
+ alias_method :ff, :fast_forward ## add alias
118
+ end
119
+
120
+
121
+ def self.push
122
+ cmd = 'git push'
123
+ Shell.run( cmd )
124
+ end
125
+
126
+ def self.add( *pathspecs ) ## e.g. git add . or git add *.rb or such
127
+ cmd = 'git add'
128
+ pathspecs = ['.'] if pathspecs.size == 0
129
+ cmd << " #{pathspecs.join('')}"
130
+ Shell.run( cmd )
131
+ end
132
+
133
+ def self.add_all
134
+ cmd = 'git add --all'
135
+ Shell.run( cmd )
136
+ end
137
+
138
+ def self.commit( message )
139
+ ### todo/check: make message.nil? an ArgumentError - why? why not?
140
+ ### if message.nil? || message.empty?
141
+
142
+ cmd = 'git commit'
143
+ cmd << %Q{ -m "#{message}"}
144
+
145
+ Shell.run( cmd )
146
+ end
147
+
148
+
149
+ #############
150
+ # change git ls-files to git ls-tree ... - why? why not?
151
+ ## - note: git ls-files will include stages files too
152
+ # not only committed ones!!!
153
+ #
154
+ # git ls-tree --full-tree --name-only -r HEAD
155
+ # 1) --full-tree makes the command run as if you were in the repo's root directory.
156
+ # 2) -r recurses into subdirectories. Combined with --full-tree, this gives you all committed, tracked files.
157
+ # 3) --name-only removes SHA / permission info for when you just want the file paths.
158
+ # 4) HEAD specifies which branch you want the list of tracked, committed files for.
159
+ # You could change this to master or any other branch name, but HEAD is the commit you have checked out right now.
160
+ #
161
+ # see https://stackoverflow.com/questions/15606955/how-can-i-make-git-show-a-list-of-the-files-that-are-being-tracked
162
+ #
163
+ # was:
164
+
165
+ def self.files ## was: e.g. git ls-files . or git ls-files *.rb or such
166
+ ### todo/check: include --full-tree - why? why not?
167
+ ## will ALWAYS list all files NOT depending on (current) working directory
168
+
169
+ cmd = 'git ls-tree --full-tree --name-only -r HEAD' # was: 'git ls-files'
170
+ Shell.run( cmd )
171
+ end
172
+ ## add list_files or ls_files alias - why? why not?
173
+
174
+
175
+ ########
176
+ ## query git configuration helpers
177
+ def self.config( prop,
178
+ show_origin: false,
179
+ show_scope: false ) ## find a better name e.g. config_get? why? why not?
180
+ cmd = "git config"
181
+ cmd << " --show-origin" if show_origin
182
+ cmd << " --show-scope" if show_scope
183
+
184
+ if prop.is_a?( Regexp )
185
+ ## note: use Regexp#source
186
+ ## Returns the original string of the pattern.
187
+ ## e.g. /ab+c/ix.source #=> "ab+c"
188
+ ## Note that escape sequences are retained as is.
189
+ ## /\x20\+/.source #=> "\\x20\\+"
190
+ cmd << " --get-regexp #{prop.source}"
191
+ else ## assume string
192
+ cmd << " --get #{prop}"
193
+ end
194
+
195
+ Shell.run( cmd )
196
+ end
197
+
198
+
199
+ def self.branch
200
+ cmd = 'git branch'
201
+ Shell.run( cmd )
202
+ end
203
+
204
+ def self.master?
205
+ output = branch ## check for '* master'
206
+ output.split( /\r?\n/ ).include?( '* master' )
207
+ end
208
+
209
+ def self.main?
210
+ output = branch ## check for '* main'
211
+ output.split( /\r?\n/ ).include?('* main')
212
+ end
213
+
214
+ ## git remote update will update all of your branches
215
+ ## set to track remote ones, but not merge any changes in.
216
+ ##
217
+ ## git fetch --all didn't exist at one time, so git remote update what more useful.
218
+ ## Now that --all has been added to git fetch, git remote update is not really necessary.
219
+ ##
220
+ ## Differences between git remote update and fetch?
221
+ ## Is git remote update the equivalent of git fetch?
222
+ ## see https://stackoverflow.com/questions/1856499/differences-between-git-remote-update-and-fetch/17512004#17512004
223
+ ##
224
+ ## git fetch learned --all and --multiple options,
225
+ ## to run fetch from many repositories,
226
+ ## and --prune option to remove remote tracking branches that went stale.
227
+ ## These make git remote update and git remote prune less necessary
228
+ ## (there is no plan to remove remote update nor remote prune, though).
229
+ def self.update
230
+ cmd = 'git remote update'
231
+ Shell.run( cmd )
232
+ end
233
+
234
+
235
+ def self.origin ## e.g. git remote show origin
236
+ cmd = "git remote show origin"
237
+ Shell.run( cmd )
238
+ end
239
+
240
+ def self.upstream ## e.g. git remote show origin
241
+ cmd = "git remote show upstream"
242
+ Shell.run( cmd )
243
+ end
244
+
245
+ def self.remote
246
+ cmd = "git remote"
247
+ Shell.run( cmd )
248
+ end
249
+
250
+ def self.origin?
251
+ output = remote ## check for 'origin'
252
+ output.split( /\r?\n/ ).include?( 'origin' )
253
+ end
254
+
255
+ def self.upstream?
256
+ output = remote ## check for 'upstream'
257
+ output.split( /\r?\n/ ).include?( 'upstream' )
258
+ end
259
+
260
+
261
+
262
+ def self.check ## e.g. git fsck - check/validate hash of objects
263
+ cmd = "git fsck"
264
+ Shell.run( cmd )
265
+ end
266
+ class << self
267
+ alias_method :fsck, :check ## add alias
268
+ alias_method :checksum, :check
269
+ end
270
+
271
+
272
+
273
+ ###
274
+ # use nested class for "base" for running commands - why? why not?
275
+ class Shell
276
+ def self.run( cmd )
277
+ print "cmd exec >#{cmd}<..."
278
+ stdout, stderr, status = Open3.capture3( cmd )
279
+
280
+ if status.success?
281
+ print " OK"
282
+ print "\n"
283
+ else
284
+ print " FAIL (#{status.exitstatus})"
285
+ print "\n"
286
+ end
287
+
288
+ unless stdout.empty?
289
+ puts stdout
290
+ end
291
+
292
+ unless stderr.empty?
293
+ ## todo/check: or use >2: or &2: or such
294
+ ## stderr output not always an error (that is, exit status might be 0)
295
+ puts "2>"
296
+ puts stderr
297
+ end
298
+
299
+ if status.success?
300
+ stdout # return stdout string
301
+ else
302
+ puts "!! ERROR: cmd exec >#{cmd}< failed with exit status #{status.exitstatus}:"
303
+ puts stderr
304
+
305
+ ### todo/fix: do NOT use GitError here!!! make it more "general"
306
+ ### use a Git::Shell.run() wrapper or such - why? why not?
307
+ ## or use a Shell.git() or Shell.git_run() ???
308
+ ## or pass in error class - why? why not?
309
+ raise GitError, "cmd exec >#{cmd}< failed with exit status #{status.exitstatus}<: #{stderr}"
310
+ end
311
+ end
312
+ end # class Git::Shell
313
+
314
+ end # class Git
315
+
316
+ 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 = 2
6
- PATCH = 0
10
+ MINOR = 4
11
+ PATCH = 2
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.2.0
4
+ version: 0.4.2
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-22 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,32 +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
70
- - lib/gitti/support/reposet.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
71
60
  - lib/gitti/version.rb
72
- homepage: https://github.com/rubylibs/gitti
61
+ - test/helper.rb
62
+ - test/test_base.rb
63
+ homepage: https://github.com/rubycoco/gitti
73
64
  licenses:
74
65
  - Public Domain
75
66
  metadata: {}
@@ -83,7 +74,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
83
74
  requirements:
84
75
  - - ">="
85
76
  - !ruby/object:Gem::Version
86
- version: 1.9.2
77
+ version: 2.2.2
87
78
  required_rubygems_version: !ruby/object:Gem::Requirement
88
79
  requirements:
89
80
  - - ">="
@@ -91,8 +82,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
91
82
  version: '0'
92
83
  requirements: []
93
84
  rubyforge_project:
94
- rubygems_version: 2.2.3
85
+ rubygems_version: 2.5.2
95
86
  signing_key:
96
87
  specification_version: 4
97
- summary: gitti - (yet) another (lite) git command line wrapper / library
88
+ summary: gitti - (yet) another (lite) git command line helper / wrapper
98
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??
@@ -1,37 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Gitti
4
-
5
-
6
- class GitRepoSet ## todo: rename to Hash/Dict/List/Map or use GitHubRepoSet ??
7
-
8
- def self.from_file( path )
9
- hash = YAML.load_file( path )
10
- self.new( hash )
11
- end
12
-
13
-
14
- def initialize( hash )
15
- @hash = hash
16
- end
17
-
18
- def each
19
- @hash.each do |key_with_counter,values|
20
-
21
- ## remove optional number from key e.g.
22
- ## mrhydescripts (3) => mrhydescripts
23
- ## footballjs (4) => footballjs
24
- ## etc.
25
-
26
- key = key_with_counter.sub( /\s+\([0-9]+\)/, '' )
27
-
28
- puts " -- #{key_with_counter} [#{key}] --"
29
-
30
- yield( key, values )
31
- end
32
- end
33
-
34
- end ## class GitRepoSet
35
-
36
- end ## module Gitti
37
-