fcom 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1a9b5f97f93fe24acc44065291ffb501679421adbbe099a944f4c04288d599e1
4
+ data.tar.gz: 5cf9ee105891ae2a84fd6c46bac5cfe368f7ec1b896c9cdd49ef618c8498c1f7
5
+ SHA512:
6
+ metadata.gz: d764a10321efa1264e4d5b9b9a9d51b1e2964789f36a4660017e1c0c0d04edb6859c266649dc922e3374a65f28590ca36d3396eabd1f67ce4dfd125bf7bf4297
7
+ data.tar.gz: 0ed2904a35496b5a8d848f3dfc8adfdcf7af1b3af7bb019df8373ad34930fc142cae5def0af3dae9e43d86c94c36b52e5dde66171a9f0511240e3fe58011c9b3
@@ -0,0 +1,8 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: weekly
7
+ time: "03:52"
8
+ timezone: America/Chicago
@@ -0,0 +1,23 @@
1
+ name: Run Rspec Tests
2
+
3
+ on:
4
+ pull_request:
5
+ branches:
6
+ - master
7
+
8
+ jobs:
9
+ build:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v3
13
+ - uses: ruby/setup-ruby@v1
14
+ with:
15
+ bundler-cache: true
16
+ - name: Run Rubocop
17
+ run: bin/rubocop --format clang
18
+ - name: Run RSpec tests
19
+ run: bin/rspec --format progress
20
+ - name: Ensure alpha version
21
+ run: grep alpha $(find . -type f -name version.rb)
22
+ - name: Ensure no git diff
23
+ run: git diff --exit-code && git diff-index --quiet --cached HEAD
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
@@ -0,0 +1,3 @@
1
+ ---
2
+ git: true
3
+ rubygems: true
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,6 @@
1
+ inherit_gem:
2
+ runger_style:
3
+ - rulesets/default.yml # gem 'rubocop'
4
+ - rulesets/performance.yml # gem 'rubocop-performance'
5
+ - rulesets/rake.yml # gem 'rubocop-rake'
6
+ - rulesets/rspec.yml # gem 'rubocop-rspec'
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.2.2
data/CHANGELOG.md ADDED
@@ -0,0 +1,125 @@
1
+ ## v0.4.1 (2023-05-04)
2
+ [no unreleased changes yet]
3
+
4
+ ## v0.4.0 (2022-09-29)
5
+ [no unreleased changes yet]
6
+
7
+ ## v0.3.4 (2021-01-26)
8
+ ### Dependencies
9
+ - Bump `release_assistant` to `0.1.1.alpha`
10
+
11
+ ## v0.3.3 (2021-01-26)
12
+ ### Internal
13
+ - Source Rubocop rules/config from `runger_style` gem
14
+ - Use `release_assistant` to manage releases
15
+ - Ensure in PR CI runs that the current version contains "alpha" & that there's no git diff (e.g.
16
+ due to failing to run `bundle` after updating the version)
17
+
18
+ ## 0.3.2 - 2020-06-13
19
+ ### Tests
20
+ - Extract RSpec performance summary reporting to a gem
21
+ ([rspec_performance_summary](https://github.com/davidrunger/rspec_performance_summary/))
22
+
23
+ ## 0.3.1 - 2020-06-06
24
+ ### Docs
25
+ - Add note to README.md about `--init` option
26
+
27
+ ## 0.3.0 - 2020-06-06
28
+ ### Added
29
+ - Add `--init` flag to automatically create an `.fcom.yml` file
30
+
31
+ ## 0.2.19 - 2020-06-05
32
+ ### Docs
33
+ - Add badges to README.md (CI status, dependabot status, tag/version)
34
+
35
+ ## 0.2.18 - 2020-06-05
36
+ ### Tests
37
+ - Stub `ConfigFileOptions#config_file_exists?` to return `false` in tests
38
+
39
+ ## 0.2.17 - 2020-06-05
40
+ ### Fixed
41
+ - Print warning about missing `.fcom.yml` config file before executing querier
42
+
43
+ ## 0.2.16 - 2020-06-05
44
+ ### Tests
45
+ - Don't print debug statement(s) when executing tests
46
+
47
+ ## 0.2.15 - 2020-06-05
48
+ ### Fixed
49
+ - Don't print empty spaces before the first matching commit
50
+
51
+ ## 0.2.14 - 2020-06-05
52
+ ### Added
53
+ - Print warning if `.fcom.yml` config file does not exist (or it does not specify a `repo` option)
54
+
55
+ ## 0.2.13 - 2020-06-05
56
+ ### Added
57
+ - Add support for an `.fcom.yml` config file (supporting only a `repo` option at this time)
58
+
59
+ ## 0.2.12 - 2020-06-05
60
+ ### Docs
61
+ - Update the illustrated `--help` output in `README.md` to reflect the `-i`/`--ignore-case` and
62
+ `--debug` options.
63
+
64
+ ## 0.2.11 - 2020-06-05
65
+ ### Tests
66
+ - Added logging of how long each example takes to execute
67
+ - Stubbed `Fcom::GitHelpers#repo` in tests to improve spec performance
68
+
69
+ ## 0.2.10 - 2020-06-05
70
+ ### Changed
71
+ - Set `Fcom.logger.level` for both querier and parser
72
+
73
+ ## 0.2.9 - 2020-06-05
74
+ ### Changed
75
+ - Specify dependency versions
76
+
77
+ ## 0.2.8 - 2020-06-05
78
+ ## Added
79
+ - Add `--debug` option and only print the command(s) being executed if that option is used
80
+
81
+ ## Fixed
82
+ - Added `activesupport` as a dependency of the `fcom` gem in the gemspec
83
+
84
+ ## Changed
85
+ - Removed version locks for dependencies in gemspec
86
+
87
+ ## 0.2.7 - 2020-06-05
88
+ ### Maintenance
89
+ - Added release script
90
+
91
+ ## 0.2.6 - 2020-06-05
92
+ ### Added
93
+ - Allow searching case-insensitively via `-i`/`--ignore-case` option
94
+
95
+ ## 0.2.5 - 2020-06-05
96
+ ### Added
97
+ - Allow filtering results to a specific path (directory or file) via `-p`/`--path` option
98
+
99
+ ### Tests
100
+ - Don't send email notifications about Travis build results
101
+
102
+ ## 0.2.4 - 2019-12-31
103
+ ### Tests
104
+ - Added tests
105
+
106
+ ## 0.2.3 - 2019-12-29
107
+ ### Added
108
+ - Determine default repo name from git origin remote, if possible
109
+
110
+ ## 0.2.2 - 2019-12-28
111
+ ### Changed
112
+ - Improved documentation
113
+
114
+ ## 0.2.1 - 2019-12-28
115
+ ### Added
116
+ - Add `--repo` option, which is used in the GitHub links that are printed for matching commits
117
+
118
+ ## 0.2.0 - 2019-12-28
119
+ ### Breaking changes
120
+ - Change how options should be provided to the `fcom` command
121
+ - Parse command argument/options with `slop` gem
122
+
123
+ ## 0.1.0 - 2019-12-28
124
+ ### Added
125
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ ruby '3.2.2'
4
+
5
+ source 'https://rubygems.org'
6
+
7
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
8
+
9
+ # Specify your gem's dependencies in fcom.gemspec
10
+ gemspec
11
+
12
+ group :development, :test do
13
+ gem 'bundler', require: false
14
+ gem 'pry'
15
+ gem 'pry-byebug'
16
+ gem 'rake', require: false
17
+ gem 'rspec', require: false
18
+ gem 'rubocop', require: false
19
+ gem 'rubocop-performance', require: false
20
+ gem 'rubocop-rake', require: false
21
+ gem 'rubocop-rspec', require: false
22
+ gem 'runger_style', github: 'davidrunger/runger_style', require: false
23
+ end
24
+
25
+ group :development do
26
+ gem 'release_assistant', require: false, github: 'davidrunger/release_assistant'
27
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,122 @@
1
+ GIT
2
+ remote: https://github.com/davidrunger/release_assistant
3
+ revision: 969b3a90264da6ce73275a7240cc7e54ff5a6370
4
+ specs:
5
+ release_assistant (0.3.3.alpha)
6
+ activesupport (>= 6, < 8)
7
+ colorize (~> 0.8)
8
+ memoist (~> 0.16)
9
+ slop (~> 4.8)
10
+
11
+ GIT
12
+ remote: https://github.com/davidrunger/runger_style
13
+ revision: 3d9d3a91cfd39a037ef4b0dbb547d4b652f7bc4e
14
+ specs:
15
+ runger_style (0.2.22.alpha)
16
+ rubocop (>= 1.38.0, < 2)
17
+
18
+ PATH
19
+ remote: .
20
+ specs:
21
+ fcom (0.4.1)
22
+ activesupport (>= 6, < 8)
23
+ colorize (~> 0.8)
24
+ memoist (~> 0.16)
25
+ slop (~> 4.8)
26
+
27
+ GEM
28
+ remote: https://rubygems.org/
29
+ specs:
30
+ activesupport (7.0.4.3)
31
+ concurrent-ruby (~> 1.0, >= 1.0.2)
32
+ i18n (>= 1.6, < 2)
33
+ minitest (>= 5.1)
34
+ tzinfo (~> 2.0)
35
+ ast (2.4.2)
36
+ byebug (11.1.3)
37
+ coderay (1.1.3)
38
+ colorize (0.8.1)
39
+ concurrent-ruby (1.2.2)
40
+ diff-lcs (1.5.0)
41
+ i18n (1.12.0)
42
+ concurrent-ruby (~> 1.0)
43
+ json (2.6.3)
44
+ memoist (0.16.2)
45
+ method_source (1.0.0)
46
+ minitest (5.18.0)
47
+ parallel (1.23.0)
48
+ parser (3.2.2.1)
49
+ ast (~> 2.4.1)
50
+ pry (0.14.2)
51
+ coderay (~> 1.1)
52
+ method_source (~> 1.0)
53
+ pry-byebug (3.10.1)
54
+ byebug (~> 11.0)
55
+ pry (>= 0.13, < 0.15)
56
+ rainbow (3.1.1)
57
+ rake (13.0.6)
58
+ regexp_parser (2.8.0)
59
+ rexml (3.2.5)
60
+ rspec (3.12.0)
61
+ rspec-core (~> 3.12.0)
62
+ rspec-expectations (~> 3.12.0)
63
+ rspec-mocks (~> 3.12.0)
64
+ rspec-core (3.12.0)
65
+ rspec-support (~> 3.12.0)
66
+ rspec-expectations (3.12.0)
67
+ diff-lcs (>= 1.2.0, < 2.0)
68
+ rspec-support (~> 3.12.0)
69
+ rspec-mocks (3.12.0)
70
+ diff-lcs (>= 1.2.0, < 2.0)
71
+ rspec-support (~> 3.12.0)
72
+ rspec-support (3.12.0)
73
+ rubocop (1.50.2)
74
+ json (~> 2.3)
75
+ parallel (~> 1.10)
76
+ parser (>= 3.2.0.0)
77
+ rainbow (>= 2.2.2, < 4.0)
78
+ regexp_parser (>= 1.8, < 3.0)
79
+ rexml (>= 3.2.5, < 4.0)
80
+ rubocop-ast (>= 1.28.0, < 2.0)
81
+ ruby-progressbar (~> 1.7)
82
+ unicode-display_width (>= 2.4.0, < 3.0)
83
+ rubocop-ast (1.28.1)
84
+ parser (>= 3.2.1.0)
85
+ rubocop-capybara (2.18.0)
86
+ rubocop (~> 1.41)
87
+ rubocop-performance (1.17.1)
88
+ rubocop (>= 1.7.0, < 2.0)
89
+ rubocop-ast (>= 0.4.0)
90
+ rubocop-rake (0.6.0)
91
+ rubocop (~> 1.0)
92
+ rubocop-rspec (2.20.0)
93
+ rubocop (~> 1.33)
94
+ rubocop-capybara (~> 2.17)
95
+ ruby-progressbar (1.13.0)
96
+ slop (4.10.1)
97
+ tzinfo (2.0.6)
98
+ concurrent-ruby (~> 1.0)
99
+ unicode-display_width (2.4.2)
100
+
101
+ PLATFORMS
102
+ ruby
103
+
104
+ DEPENDENCIES
105
+ bundler
106
+ fcom!
107
+ pry
108
+ pry-byebug
109
+ rake
110
+ release_assistant!
111
+ rspec
112
+ rubocop
113
+ rubocop-performance
114
+ rubocop-rake
115
+ rubocop-rspec
116
+ runger_style!
117
+
118
+ RUBY VERSION
119
+ ruby 3.2.2p53
120
+
121
+ BUNDLED WITH
122
+ 2.4.12
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 David Runger
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,100 @@
1
+ [![Build Status](https://travis-ci.org/davidrunger/fcom.svg?branch=master)](https://travis-ci.org/davidrunger/fcom)
2
+ [![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=davidrunger/fcom)](https://dependabot.com)
3
+ ![GitHub tag (latest SemVer pre-release)](https://img.shields.io/github/v/tag/davidrunger/fcom?include_prereleases)
4
+
5
+ # `fcom` ("find commit(s)")
6
+
7
+ This is a CLI tool that I use to parse the git history of a repo.
8
+
9
+ For example, if I use `fcom` to search this repo with `fcom "line.(green|red)" --regex --repo
10
+ davidrunger/fcom`, I get this output:
11
+
12
+ ![](https://s3.amazonaws.com/screens.davidrunger.com/2019-12-28-20-50-09-oect2(1).png)
13
+
14
+ ## Installation
15
+
16
+ ```
17
+ gem install fcom
18
+ ```
19
+
20
+ ## Dependencies
21
+
22
+ This gem assumes that you have `git` and [`rg` (ripgrep)][ripgrep] installed.
23
+
24
+ [ripgrep]: https://github.com/BurntSushi/ripgrep
25
+
26
+ ## Basic usage
27
+
28
+ ```
29
+ $ fcom <search string> [options]
30
+ ```
31
+
32
+ #### Available options and examples
33
+
34
+ After installing, execute `fcom --help` to see usage examples and available options.
35
+
36
+ ```
37
+ $ fcom --help
38
+
39
+ Usage: fcom <search string> [options]
40
+
41
+ Examples:
42
+ fcom update
43
+ fcom 'def update'
44
+ fcom "def update" --days 60
45
+ fcom "[Uu]ser.*slug" -d 365 --regex
46
+ fcom options --path spec/
47
+ fcom "line.(green|red)" -d 365 --regex --repo davidrunger/fcom -a "David Runger"
48
+
49
+ --repo GitHub repo (in form `username/repo`)
50
+ -d, --days number of days to search back
51
+ -r, --regex interpret search string as a regular expression
52
+ -i, --ignore-case search case-insensitively
53
+ -p, --path path (directory or file) used to filter results
54
+ -a, --author author
55
+ --rg-options additional options passed directly to `rg` (e.g. `--rg-options "--max-columns 1000"`)
56
+ --debug print debugging info
57
+ --init create an `.fcom.yml` config file
58
+ -v, --version print the version
59
+ -h, --help print this help information
60
+ ```
61
+
62
+ ## `.fcom.yml` config file
63
+ We highly recommend that you create an `.fcom.yml` file in any repository that you plan to search
64
+ with `fcom`.
65
+
66
+ **This file can be created automatically by executing `fcom --init`** in the relevant
67
+ repo/directory.
68
+
69
+ (You might (or might not) want to add `.fcom.yml` to your `~/.gitignore_global` file, so that this
70
+ file is not tracked by `git`.)
71
+
72
+ #### Example `.fcom.yml` config file
73
+ ```yaml
74
+ repo: githubusername/reponame
75
+ ```
76
+
77
+ The advantage of creating an `.fcom.yml` config file is that it will make the `fcom` command execute
78
+ more quickly, because time will not be wasted parsing the output of `git remote [...]` in order to
79
+ determine the URL of the repo's remote repository (which is used to construct links to matching
80
+ commits).
81
+
82
+ ## Development
83
+
84
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run
85
+ the tests. You can also run `bin/console` for an interactive prompt that will allow you to
86
+ experiment.
87
+
88
+ To install this gem onto your local machine, run (in this repository's root directory):
89
+
90
+ ```
91
+ $ rm -f pkg/*.gem && rake build && gem install --local pkg/fcom-*.gem
92
+ ```
93
+
94
+ ## Contributing
95
+
96
+ Bug reports and pull requests are welcome on GitHub at https://github.com/davidrunger/fcom.
97
+
98
+ ## License
99
+
100
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/RELEASING.md ADDED
@@ -0,0 +1,7 @@
1
+ To release a new version, run `bin/release` with an appropriate `--type` option, e.g.:
2
+
3
+ ```
4
+ bin/release --type minor
5
+ ```
6
+
7
+ (This uses the `release_assistant` gem.)
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task(default: :spec)
data/bin/_guard-core ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application '_guard-core' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', Pathname.new(__FILE__).realpath)
13
+
14
+ bundle_binstub = File.expand_path('bundle', __dir__)
15
+
16
+ if File.file?(bundle_binstub)
17
+ if File.read(bundle_binstub, 300).include?('This file was generated by Bundler')
18
+ load(bundle_binstub)
19
+ else
20
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
21
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
22
+ end
23
+ end
24
+
25
+ require 'rubygems'
26
+ require 'bundler/setup'
27
+
28
+ load Gem.bin_path('guard', '_guard-core')
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'fcom'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
data/bin/guard ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'guard' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', Pathname.new(__FILE__).realpath)
13
+
14
+ bundle_binstub = File.expand_path('bundle', __dir__)
15
+
16
+ if File.file?(bundle_binstub)
17
+ if File.read(bundle_binstub, 300).include?('This file was generated by Bundler')
18
+ load(bundle_binstub)
19
+ else
20
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
21
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
22
+ end
23
+ end
24
+
25
+ require 'rubygems'
26
+ require 'bundler/setup'
27
+
28
+ load Gem.bin_path('guard', 'guard')
data/bin/release ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'release' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', Pathname.new(__FILE__).realpath)
13
+
14
+ bundle_binstub = File.expand_path('bundle', __dir__)
15
+
16
+ if File.file?(bundle_binstub)
17
+ if File.read(bundle_binstub, 300).include?('This file was generated by Bundler')
18
+ load(bundle_binstub)
19
+ else
20
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
21
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
22
+ end
23
+ end
24
+
25
+ require 'rubygems'
26
+ require 'bundler/setup'
27
+
28
+ load Gem.bin_path('release_assistant', 'release')
data/bin/rspec ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rspec' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', Pathname.new(__FILE__).realpath)
13
+
14
+ bundle_binstub = File.expand_path('bundle', __dir__)
15
+
16
+ if File.file?(bundle_binstub)
17
+ if File.read(bundle_binstub, 300).include?('This file was generated by Bundler')
18
+ load(bundle_binstub)
19
+ else
20
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
21
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
22
+ end
23
+ end
24
+
25
+ require 'rubygems'
26
+ require 'bundler/setup'
27
+
28
+ load Gem.bin_path('rspec-core', 'rspec')
data/bin/rubocop ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rubocop' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', Pathname.new(__FILE__).realpath)
13
+
14
+ bundle_binstub = File.expand_path('bundle', __dir__)
15
+
16
+ if File.file?(bundle_binstub)
17
+ if File.read(bundle_binstub, 300).include?('This file was generated by Bundler')
18
+ load(bundle_binstub)
19
+ else
20
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
21
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
22
+ end
23
+ end
24
+
25
+ require 'rubygems'
26
+ require 'bundler/setup'
27
+
28
+ load Gem.bin_path('rubocop', 'rubocop')
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/exe/fcom ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require 'slop'
6
+ require_relative '../lib/fcom.rb'
7
+
8
+ opts =
9
+ Slop.parse do |o|
10
+ o.banner = <<~BANNER
11
+
12
+ Usage: fcom <search string> [options]
13
+
14
+ Examples:
15
+ fcom update
16
+ fcom 'def update'
17
+ fcom "def update" --days 60
18
+ fcom "[Uu]ser.*slug" -d 365 --regex
19
+ fcom options --path spec/
20
+ fcom "line.(green|red)" -d 365 --regex --repo davidrunger/fcom -a "David Runger"
21
+ BANNER
22
+
23
+ Fcom.define_slop_options(o)
24
+
25
+ o.on('--init', 'create an `.fcom.yml` config file') do
26
+ File.write('.fcom.yml', "repo: #{Fcom::GitHelpers.new.repo}\n")
27
+ puts('Created `.fcom.yml` file!'.green.bold)
28
+ exit
29
+ end
30
+ o.on('-v', '--version', 'print the version') do
31
+ puts(Fcom::VERSION)
32
+ exit
33
+ end
34
+ o.on('-h', '--help', 'print this help information') do
35
+ puts(o)
36
+ exit
37
+ end
38
+ end
39
+
40
+ # Note: mutating the globally accessible `Fcom.logger` constant like this is not thread-safe
41
+ Fcom.logger.level = Logger::DEBUG if opts.debug?
42
+
43
+ if opts.parse_mode?
44
+ Fcom::Parser.new(opts).parse
45
+ elsif !opts.arguments.empty?
46
+ Fcom.warn_if_config_file_repo_option_missing
47
+ Fcom::Querier.new(opts).query
48
+ else
49
+ puts(opts.options)
50
+ end
data/fcom.gemspec ADDED
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/fcom/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'fcom'
7
+ spec.version = Fcom::VERSION
8
+ spec.authors = ['David Runger']
9
+ spec.email = ['davidjrunger@gmail.com']
10
+
11
+ spec.summary = 'CLI tool for parsing git history'
12
+ spec.homepage = 'https://github.com/davidrunger/fcom'
13
+ spec.license = 'MIT'
14
+
15
+ if spec.respond_to?(:metadata)
16
+ spec.metadata['rubygems_mfa_required'] = 'true'
17
+
18
+ spec.metadata['homepage_uri'] = spec.homepage
19
+ spec.metadata['source_code_uri'] = 'https://github.com/davidrunger/fcom'
20
+ spec.metadata['changelog_uri'] = 'https://github.com/davidrunger/fcom/blob/master/CHANGELOG.md'
21
+ else
22
+ raise('RubyGems 2.0 or newer is required to protect against public gem pushes.')
23
+ end
24
+
25
+ # Specify which files should be added to the gem when it is released.
26
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
27
+ spec.files =
28
+ Dir.chdir(File.expand_path(__dir__)) do
29
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
30
+ end
31
+ spec.bindir = 'exe'
32
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
33
+ spec.require_paths = ['lib']
34
+
35
+ spec.add_dependency('activesupport', '>= 6', '< 8')
36
+ spec.add_dependency('colorize', '~> 0.8')
37
+ spec.add_dependency('memoist', '~> 0.16')
38
+ spec.add_dependency('slop', '~> 4.8')
39
+
40
+ spec.required_ruby_version = '>= 3.2'
41
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Fcom::ConfigFileOptions
4
+ extend Memoist
5
+
6
+ def initialize
7
+ @options =
8
+ if config_file_exists?
9
+ YAML.load_file(config_file_path)
10
+ else
11
+ {}
12
+ end
13
+ end
14
+
15
+ def repo
16
+ @options['repo']
17
+ end
18
+
19
+ private
20
+
21
+ memoize \
22
+ def config_file_path
23
+ "#{ENV.fetch('PWD')}/.fcom.yml"
24
+ end
25
+
26
+ def config_file_exists?
27
+ File.exist?(config_file_path)
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This class contains helpers that extract information from `git`.
4
+ class Fcom::GitHelpers
5
+ def repo
6
+ # Examples:
7
+ # git@github.com:davidrunger/fcom.git
8
+ # https://github.com/davidrunger/fcom.git
9
+ # https://github.com/davidrunger/fcom
10
+ origin_fetch_url.delete_suffix('/').match(%r{github\.com[:/](((?!\.git).)*)})[1]
11
+ end
12
+
13
+ private
14
+
15
+ def origin_fetch_url
16
+ origin_remote_info = `git remote -v`
17
+ origin_remote_info.match(/origin\s+(.*)\s+\(fetch\)$/)[1]
18
+ end
19
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This module contains convenience methods that expose more directly the command options provided.
4
+ module Fcom::OptionsHelpers
5
+ private
6
+
7
+ def author
8
+ @options[:author]
9
+ end
10
+
11
+ def days
12
+ @options[:days]
13
+ end
14
+
15
+ def ignore_case?
16
+ @options.ignore_case?
17
+ end
18
+
19
+ def path
20
+ @options[:path]
21
+ end
22
+
23
+ def regex_mode?
24
+ @options.regex?
25
+ end
26
+
27
+ def debug?
28
+ @options.debug?
29
+ end
30
+
31
+ def development?
32
+ @options.development?
33
+ end
34
+
35
+ def repo
36
+ @options[:repo]
37
+ end
38
+
39
+ def search_string
40
+ @options.arguments.first
41
+ end
42
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This class parses (and then reprints some of) STDIN according to the options passed to `fcom`.
4
+ class Fcom::Parser
5
+ include ::Fcom::OptionsHelpers
6
+
7
+ def initialize(options)
8
+ @options = options
9
+ end
10
+
11
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
12
+ # rubocop:disable Metrics/MethodLength
13
+ def parse
14
+ expression_to_match = search_string
15
+ expression_to_match = Regexp.escape(expression_to_match).gsub('\\ ', ' ') unless regex_mode?
16
+ regex =
17
+ Regexp.new(
18
+ "((\\+|-)\\s?.*#{expression_to_match}.*|Omitted long (matching )?line)",
19
+ ignore_case? ? Regexp::IGNORECASE : nil,
20
+ )
21
+
22
+ previous_commit = nil
23
+ a_commit_has_matched = false
24
+ filename = nil
25
+ $stdin.each do |line|
26
+ line.chomp!
27
+ if (match = line.match(/^commit (.*)/)&.[](1))
28
+ previous_commit = match
29
+ elsif line.match?(/^diff /)
30
+ old_filename = line.match(%r{ a/(\S+)})&.[](1) || '[weird filename]'
31
+ new_filename = line.match(%r{ b/(\S+)})&.[](1) || '[weird filename]'
32
+ filename =
33
+ case
34
+ when old_filename == new_filename then old_filename
35
+ else "#{old_filename} --> #{new_filename}"
36
+ end
37
+ elsif line.match?(regex) && (filename.blank? || path_match?(filename))
38
+ if previous_commit
39
+ title, sha, author, date = previous_commit.split('|')
40
+ sha_with_url = "#{sha[0, 7]} ( https://github.com/#{repo}/commit/#{sha[0, 7]} )"
41
+
42
+ puts("\n\n") if a_commit_has_matched # print commit separator, if needed
43
+ puts([title, sha_with_url, author, date])
44
+ puts('==============================================')
45
+
46
+ previous_commit = nil
47
+ a_commit_has_matched = true
48
+ end
49
+
50
+ if filename
51
+ puts(filename)
52
+ filename = nil
53
+ end
54
+
55
+ if line.start_with?('+')
56
+ puts(line.green)
57
+ elsif line.start_with?('-')
58
+ puts(line.red)
59
+ else
60
+ puts(line)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ # rubocop:enable Metrics/MethodLength
66
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
67
+
68
+ private
69
+
70
+ def path_match?(filename)
71
+ return true if path == Fcom::ROOT_PATH
72
+
73
+ filename.include?(path.delete_prefix('./'))
74
+ end
75
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './options_helpers.rb'
4
+
5
+ # This class executes a system command to retrieve the git history, which is passed through `rg`
6
+ # (ripgrep), and then ultimately is fed back to `fcom` for parsing.
7
+ class Fcom::Querier
8
+ include ::Fcom::OptionsHelpers
9
+
10
+ def initialize(options)
11
+ @options = options
12
+ end
13
+
14
+ # rubocop:disable Metrics/CyclomaticComplexity
15
+ # rubocop:disable Metrics/PerceivedComplexity
16
+ def query
17
+ expression_to_match = search_string
18
+ expression_to_match = Regexp.escape(expression_to_match).gsub('\\ ', ' ') unless regex_mode?
19
+
20
+ if expression_to_match.nil? || expression_to_match.empty?
21
+ puts('provide expression to match as first argument')
22
+ exit
23
+ end
24
+
25
+ quote = expression_to_match.include?('"') ? "'" : '"'
26
+
27
+ command = <<~COMMAND.squish
28
+ git log
29
+ #{%(--author="#{author}") if author}
30
+ #{"--since=#{days}.day" unless days.nil?}
31
+ --full-diff
32
+ --no-textconv
33
+ --format="commit %s|%H|%an|%cr (%ci)"
34
+ --source
35
+ -p #{path}
36
+ |
37
+
38
+ rg #{quote}(#{expression_to_match})|(^commit )|(^diff )#{quote}
39
+ --color never
40
+ #{'--ignore-case' if ignore_case?}
41
+ #{@options[:rg_options]}
42
+ |
43
+
44
+ #{'exe/' if development?}fcom #{quote}#{search_string}#{quote}
45
+ #{"--days #{days}" if days}
46
+ #{'--regex' if regex_mode?}
47
+ #{'--debug' if debug?}
48
+ #{'--ignore-case' if ignore_case?}
49
+ --path #{path}
50
+ --parse-mode
51
+ --repo #{repo}
52
+ COMMAND
53
+
54
+ Fcom.logger.debug("Executing command: #{command}")
55
+ system(command)
56
+ end
57
+ # rubocop:enable Metrics/PerceivedComplexity
58
+ # rubocop:enable Metrics/CyclomaticComplexity
59
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Style/StaticClass
4
+ class Fcom
5
+ VERSION = '0.4.1'
6
+ end
7
+ # rubocop:enable Style/StaticClass
data/lib/fcom.rb ADDED
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/all'
4
+ require 'colorize'
5
+ require 'memoist'
6
+ require 'slop'
7
+ require 'yaml'
8
+
9
+ # This `Fcom` class is the namespace within which most of the gem's code is written.
10
+ # We need to define the class before requiring the modules.
11
+ # rubocop:disable Lint/EmptyClass
12
+ class Fcom
13
+ end
14
+ # rubocop:enable Lint/EmptyClass
15
+
16
+ Dir["#{File.dirname(__FILE__)}/fcom/*.rb"].each { |file| require file }
17
+
18
+ class Fcom
19
+ ROOT_PATH = '.'
20
+
21
+ class << self
22
+ extend Memoist
23
+
24
+ memoize \
25
+ def logger
26
+ Logger.new($stdout).tap do |logger|
27
+ logger.formatter = ->(_severity, _datetime, _progname, msg) { "#{msg}\n" }
28
+ # default the log level to WARN, but this can be set to `DEBUG` via the `--debug` CLI option
29
+ logger.level = Logger::WARN
30
+ end
31
+ end
32
+
33
+ memoize \
34
+ def config_file_options
35
+ Fcom::ConfigFileOptions.new
36
+ end
37
+
38
+ def warn_if_config_file_repo_option_missing
39
+ if config_file_options.repo.blank?
40
+ puts(<<~WARNING.rstrip.yellow)
41
+ Warning: you have not specified a `repo` option in an `.fcom.yml` file.
42
+ This will cause `fcom` to execute more slowly than necessary.
43
+ WARNING
44
+ puts('Execute `fcom --init` to create an `.fcom.yml` file.'.blue.bold)
45
+ puts("See https://github.com/davidrunger/fcom/#readme for more info.\n\n")
46
+ end
47
+ end
48
+
49
+ def define_slop_options(options)
50
+ git_helpers = Fcom::GitHelpers.new
51
+ default_repo = config_file_options.repo || git_helpers.repo || 'username/repo'
52
+
53
+ options.string('--repo', 'GitHub repo (in form `username/repo`)', default: default_repo)
54
+ options.integer('-d', '--days', 'number of days to search back')
55
+ options.bool(
56
+ '-r',
57
+ '--regex',
58
+ 'interpret search string as a regular expression',
59
+ default: false,
60
+ )
61
+ options.bool('-i', '--ignore-case', 'search case-insensitively', default: false)
62
+ options.string(
63
+ '-p',
64
+ '--path',
65
+ 'path (directory or file) used to filter results',
66
+ default: Fcom::ROOT_PATH,
67
+ )
68
+ options.string(
69
+ '-a',
70
+ '--author',
71
+ 'author',
72
+ )
73
+ options.string(
74
+ '--rg-options',
75
+ 'additional options passed directly to `rg` (e.g. `--rg-options "--max-columns 1000"`)',
76
+ default: '',
77
+ )
78
+ options.bool('--debug', 'print debugging info', default: false)
79
+ options.bool('--parse-mode', 'whether we are in parse mode', default: false, help: false)
80
+ options.bool('--development', 'use local `fcom` executable', default: false, help: false)
81
+ end
82
+ end
83
+ end
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fcom
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.1
5
+ platform: ruby
6
+ authors:
7
+ - David Runger
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-05-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '6'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '8'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '6'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '8'
33
+ - !ruby/object:Gem::Dependency
34
+ name: colorize
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.8'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.8'
47
+ - !ruby/object:Gem::Dependency
48
+ name: memoist
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.16'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.16'
61
+ - !ruby/object:Gem::Dependency
62
+ name: slop
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '4.8'
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '4.8'
75
+ description:
76
+ email:
77
+ - davidjrunger@gmail.com
78
+ executables:
79
+ - fcom
80
+ extensions: []
81
+ extra_rdoc_files: []
82
+ files:
83
+ - ".github/dependabot.yml"
84
+ - ".github/workflows/ruby.yml"
85
+ - ".gitignore"
86
+ - ".release_assistant.yml"
87
+ - ".rspec"
88
+ - ".rubocop.yml"
89
+ - ".ruby-version"
90
+ - CHANGELOG.md
91
+ - Gemfile
92
+ - Gemfile.lock
93
+ - LICENSE.txt
94
+ - README.md
95
+ - RELEASING.md
96
+ - Rakefile
97
+ - bin/_guard-core
98
+ - bin/console
99
+ - bin/guard
100
+ - bin/release
101
+ - bin/rspec
102
+ - bin/rubocop
103
+ - bin/setup
104
+ - exe/fcom
105
+ - fcom.gemspec
106
+ - lib/fcom.rb
107
+ - lib/fcom/config_file_options.rb
108
+ - lib/fcom/git_helpers.rb
109
+ - lib/fcom/options_helpers.rb
110
+ - lib/fcom/parser.rb
111
+ - lib/fcom/querier.rb
112
+ - lib/fcom/version.rb
113
+ homepage: https://github.com/davidrunger/fcom
114
+ licenses:
115
+ - MIT
116
+ metadata:
117
+ rubygems_mfa_required: 'true'
118
+ homepage_uri: https://github.com/davidrunger/fcom
119
+ source_code_uri: https://github.com/davidrunger/fcom
120
+ changelog_uri: https://github.com/davidrunger/fcom/blob/master/CHANGELOG.md
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '3.2'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubygems_version: 3.4.12
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: CLI tool for parsing git history
140
+ test_files: []