fcom 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 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: []