Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
gem_dating (0.1.1)
gem_dating (0.1.2)
bundler
table_print

Expand Down
53 changes: 39 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@

The primary use case is when evaluating a codebase for upgrades - a gem from 2017 may effectively be abandoned and could cause trouble if you're targeting an upgrade to Ruby 4.1

`gem_dating` avoids utilizing Bundler, and intends to be useful where you want to evaluate a set of gems without
the overhead of a full bundle install. If you've got a valid bundle you should consider the built in
[bundle-outdated](https://bundler.io/v2.4/man/bundle-outdated.1.html), or other available tools for interacting
with your Gemfile, like [libyear-bundler](https://github.com/jaredbeck/libyear-bundler).

## Usage

If you have rubygems 3.4.8 or later installed, you can skip installation and just run via `gem exec gem_dating [[path/to/Gemfile]`
Expand All @@ -22,22 +17,42 @@ If you have rubygems 3.4.8 or later installed, you can skip installation and jus
gem 'gem_dating', group: [:development], require: false
```

### Running GemDating
### Command Line Options

This gem provides a small command line interface. It may be invoked with:
GemDating supports several command line options to customize its behavior:

```bash
$ gem_dating
```
gem_dating [OPTIONS] [<GEMFILE_FILEPATH>]
```

By default, GemDating will look for a Gemfile in the current directory.
If it finds one, it will output a list of gems and their relative ages to the stdout stream.
#### Available Options:

You may also pass a path to a Gemfile as an argument:
- `--help`, `-h`, `-?`: Show the help message
- `--older-than=<AGE>`, `--ot=<AGE>`: Filter gems updated within the last X time period
- Examples: `--older-than=2y` (2 years), `--ot=1m` (1 month), `--ot=4w` (4 weeks), `--ot=10d` (10 days)
- `--sort-by=<FIELD>`: Sort by field
- Available fields: `name` or `date`
- Default: `name`
- `--order=<DIRECTION>`: Sort direction
- Available directions: `asc` (ascending) or `desc` (descending)
- Default: `asc`
- `--json`: Output results as JSON instead of table format

#### Examples:

```bash
$ gem_dating ~/code/my_app/Gemfile
```
# Show gems older than 1 year
$ gem_dating --older-than=1y

# Sort gems by date in descending order (newest first)
$ gem_dating --sort-by=date --order=desc

# Output results as JSON
$ gem_dating --json

# Combine multiple options
$ gem_dating ~/code/my_app/Gemfile --older-than=6m --sort-by=date --order=desc
```

GemDating leans on `$stdout`, so you can pipe the output to a file if you'd like:
```bash
Expand Down Expand Up @@ -86,6 +101,16 @@ more_dating.table_print
# ...etc
```

### Caveats

`gem_dating` avoids utilizing Bundler, and intends to be useful where you want to evaluate a set of gems without
the overhead of a full bundle install. If you've got a valid bundle you should consider the built in
[bundle-outdated](https://bundler.io/v2.4/man/bundle-outdated.1.html), or other available tools for interacting
with your Gemfile, like [libyear-bundler](https://github.com/jaredbeck/libyear-bundler).

Sometimes we [get incorrect dates](https://github.com/testdouble/gem_dating/issues/10).
TLDR; sometimes GemSpecs are built in an environment where the date gets overwritten. That'll be up to the gem
owner(s) to determine if they'd like to adjust it to provide accurate dates.


## Code of Conduct
Expand Down
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ Rake::TestTask.new(:test) do |t|
t.test_files = FileList["test/**/*_test.rb"]
end

task :default => :test
task default: :test
21 changes: 10 additions & 11 deletions gem_dating.gemspec
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@

lib = File.expand_path("../lib", __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require "gem_dating/version"

Gem::Specification.new do |spec|
spec.name = "gem_dating"
spec.version = GemDating::VERSION
spec.authors = ["Steve Jackson", "Daniel Huss"]
spec.email = ["steve@testdouble.com"]
spec.name = "gem_dating"
spec.version = GemDating::VERSION
spec.authors = ["Steve Jackson", "Daniel Huss"]
spec.email = ["steve@testdouble.com"]

spec.summary = "How old is that anyway?"
spec.homepage = "https://github.com/testdouble/gem_dating"
spec.license = "MIT"
spec.summary = "How old is that anyway?"
spec.homepage = "https://github.com/testdouble/gem_dating"
spec.license = "MIT"

spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"

spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]

spec.add_dependency "bundler"
Expand Down
1 change: 0 additions & 1 deletion lib/gem_dating.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ def self.from_file(path, options = {})
fetch_specs(gems, options)
end


def self.fetch_specs(gems, options)
specs = Rubygems.fetch(gems)
results = Result.new(specs)
Expand Down
2 changes: 1 addition & 1 deletion lib/gem_dating/input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def gems
end

def gem_line(line)
single_word_ruby_statements = %w{end else # gemspec}
single_word_ruby_statements = %w[end else # gemspec]
return if single_word_ruby_statements.include? line.strip

if line.start_with? "gem("
Expand Down
2 changes: 1 addition & 1 deletion lib/gem_dating/result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def to_json
end

def older_than(date)
specs.select! { |spec| spec.date.to_date < self.cut_off(date) }
specs.select! { |spec| spec.date.to_date < cut_off(date) }
self
end

Expand Down
2 changes: 1 addition & 1 deletion lib/gem_dating/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module GemDating
VERSION = "0.1.1"
VERSION = "0.1.2"
end
4 changes: 2 additions & 2 deletions test/cli_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ def test_help_option

def test_parse_args
cli = GemDating::Cli.new(["--help", "--older-than=2y"])
assert_equal({ help: true, older_than: "2y" }, cli.send(:parse_args))
assert_equal({help: true, older_than: "2y"}, cli.send(:parse_args))

cli = GemDating::Cli.new(["--json"])
assert_equal({ json: true }, cli.send(:parse_args))
assert_equal({json: true}, cli.send(:parse_args))

cli = GemDating::Cli.new([])
assert_equal({}, cli.send(:parse_args))
Expand Down
1 change: 0 additions & 1 deletion test/result_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
require "date"

class TestResult < Minitest::Test

def build_mock_spec(name:, version:, date:)
spec = Gem::Specification.new
spec.name = name
Expand Down