skippable 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7436193085c629482c33f7acdf38ec89098989c30e4acf8b004df1259bb1ba9e
4
+ data.tar.gz: 8d49e82b9f2aef5af0fe6c9b77787a25c7edaaffdf54e3e5c07cc12c6e70c6cc
5
+ SHA512:
6
+ metadata.gz: 2ee921b830b2eaefdcdffce2dfdc3dbab01b5a7261a460a0d747bb1e20f56ba9997091e96886263d2ae4851b33a583d51b0dcdef9742901beccfed058872d767
7
+ data.tar.gz: d02a4e9b981f3a2cb3fb8c9f5c619b830e7e416644c012862aabc15e8184cb3ac788e90236ae3bcb3eb8a72eb7ef070ec4b08b9553c83eaeb216de45d1025150
@@ -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
+ /spec/examples.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in skippable.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
7
+ gem "pry"
8
+
9
+ group :test do
10
+ gem "rspec", "~> 3.0"
11
+ gem "jet_black"
12
+ end
@@ -0,0 +1,42 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ skippable (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ coderay (1.1.3)
10
+ diff-lcs (1.4.4)
11
+ jet_black (0.6.0)
12
+ method_source (1.0.0)
13
+ pry (0.13.1)
14
+ coderay (~> 1.1)
15
+ method_source (~> 1.0)
16
+ rake (12.3.3)
17
+ rspec (3.10.0)
18
+ rspec-core (~> 3.10.0)
19
+ rspec-expectations (~> 3.10.0)
20
+ rspec-mocks (~> 3.10.0)
21
+ rspec-core (3.10.0)
22
+ rspec-support (~> 3.10.0)
23
+ rspec-expectations (3.10.0)
24
+ diff-lcs (>= 1.2.0, < 2.0)
25
+ rspec-support (~> 3.10.0)
26
+ rspec-mocks (3.10.0)
27
+ diff-lcs (>= 1.2.0, < 2.0)
28
+ rspec-support (~> 3.10.0)
29
+ rspec-support (3.10.0)
30
+
31
+ PLATFORMS
32
+ ruby
33
+
34
+ DEPENDENCIES
35
+ jet_black
36
+ pry
37
+ rake (~> 12.0)
38
+ rspec (~> 3.0)
39
+ skippable!
40
+
41
+ BUNDLED WITH
42
+ 2.1.4
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Oliver Peate
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.
@@ -0,0 +1,65 @@
1
+ # Skippable
2
+
3
+ Skippable helps you skip slow commands unless certain files changed. This can be
4
+ handy on CI, where valuable time, money, and CO₂ are often wasted by repeatedly
5
+ running the same command when nothing changed.
6
+
7
+ For example [License Finder](https://github.com/pivotal/LicenseFinder) takes ~45
8
+ seconds to run on a project with Ruby gems and NPM dependencies. In this example
9
+ there's no need to check the licenses if the dependency lockfiles didn't change.
10
+
11
+ ## Usage
12
+
13
+ Add Skippable to your Gemfile:
14
+
15
+ ```ruby
16
+ group :development do
17
+ gem "skippable", require: false
18
+ end
19
+ ```
20
+
21
+ Setup a `.skippable.yml` config file with one or more tasks:
22
+
23
+ ```yaml
24
+ tasks:
25
+ expensive_op:
26
+ command: bundle exec my_slow_command
27
+ paths:
28
+ - lockfile_a
29
+ - lockfile_b
30
+ ```
31
+
32
+ Run the task using `skippable`:
33
+
34
+ ```
35
+ bundle exec skippable expensive_op
36
+ ```
37
+
38
+ - If the cache was cold OR the lockfiles changed, the specified command will
39
+ be run
40
+ - If the cache is warm, and the lockfiles haven't changed, the command
41
+ will be skipped
42
+
43
+ Finally, cache the following directory to persist state across builds:
44
+
45
+ ```
46
+ tmp/skippable
47
+ ```
48
+
49
+ ## Example
50
+
51
+ ```yaml
52
+ # .skippable.yml
53
+ tasks:
54
+ license_finder:
55
+ command: bundle exec license_finder
56
+ paths:
57
+ - Gemfile.lock
58
+ - yarn.lock
59
+ ```
60
+
61
+ Invocation:
62
+
63
+ ```
64
+ bundle exec skippable license_finder
65
+ ```
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "skippable/task_loader"
4
+
5
+ task = Skippable::TaskLoader.new.by_name(ARGV.first)
6
+ exit task.call
@@ -0,0 +1,5 @@
1
+ require "skippable/version"
2
+
3
+ module Skippable
4
+ class Error < StandardError; end
5
+ end
@@ -0,0 +1,40 @@
1
+ require "digest"
2
+ require "fileutils"
3
+
4
+ module Skippable
5
+ class FileDigest
6
+ def initialize(path:)
7
+ @path = path
8
+ end
9
+
10
+ def changed?
11
+ current_digest != cached_digest
12
+ end
13
+
14
+ def update_cached_digest
15
+ unless File.directory?(File.dirname(cached_digest_path))
16
+ FileUtils.mkdir_p(File.dirname(cached_digest_path))
17
+ end
18
+
19
+ File.write(cached_digest_path, current_digest)
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :path
25
+
26
+ def current_digest
27
+ @current_digest ||= Digest::SHA256.file(path).hexdigest
28
+ end
29
+
30
+ def cached_digest
31
+ if File.exist?(cached_digest_path)
32
+ File.read(cached_digest_path)
33
+ end
34
+ end
35
+
36
+ def cached_digest_path
37
+ File.join("tmp", "skippable", path)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,38 @@
1
+ require "skippable/file_digest"
2
+
3
+ module Skippable
4
+ class Task
5
+ def initialize(name:, command:, paths:)
6
+ @name = name
7
+ @command = command
8
+ @paths = paths
9
+ end
10
+
11
+ def call
12
+ if file_digests.none?(&:changed?)
13
+ puts "Skipping #{name}..."
14
+ return 0
15
+ end
16
+
17
+ execute_command
18
+
19
+ if $?.success?
20
+ file_digests.each(&:update_cached_digest)
21
+ end
22
+
23
+ $?.exitstatus
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :name, :command, :paths
29
+
30
+ def execute_command
31
+ system(command)
32
+ end
33
+
34
+ def file_digests
35
+ @file_digests ||= paths.map { |path| FileDigest.new(path: path) }
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,22 @@
1
+ require "yaml"
2
+ require "skippable/task"
3
+
4
+ module Skippable
5
+ class TaskLoader
6
+ def by_name(task_name)
7
+ task_config = config.fetch("tasks").fetch(task_name)
8
+
9
+ Task.new(
10
+ name: task_name,
11
+ command: task_config.fetch("command"),
12
+ paths: task_config.fetch("paths"),
13
+ )
14
+ end
15
+
16
+ private
17
+
18
+ def config
19
+ @config ||= YAML.load_file(".skippable.yml")
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module Skippable
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,25 @@
1
+ require_relative "lib/skippable/version"
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "skippable"
5
+ spec.version = Skippable::VERSION
6
+ spec.authors = ["Oliver Peate"]
7
+
8
+ spec.summary = "Skip a command unless file(s) changed"
9
+ spec.homepage = "https://github.com/odlp/skippable"
10
+ spec.license = "MIT"
11
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
12
+
13
+ spec.metadata["homepage_uri"] = spec.homepage
14
+ spec.metadata["source_code_uri"] = spec.homepage
15
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
16
+
17
+ # Specify which files should be added to the gem when it is released.
18
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ end
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: skippable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Oliver Peate
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-12-22 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ executables:
16
+ - skippable
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".gitignore"
21
+ - ".rspec"
22
+ - Gemfile
23
+ - Gemfile.lock
24
+ - LICENSE.txt
25
+ - README.md
26
+ - Rakefile
27
+ - exe/skippable
28
+ - lib/skippable.rb
29
+ - lib/skippable/file_digest.rb
30
+ - lib/skippable/task.rb
31
+ - lib/skippable/task_loader.rb
32
+ - lib/skippable/version.rb
33
+ - skippable.gemspec
34
+ homepage: https://github.com/odlp/skippable
35
+ licenses:
36
+ - MIT
37
+ metadata:
38
+ homepage_uri: https://github.com/odlp/skippable
39
+ source_code_uri: https://github.com/odlp/skippable
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: 2.3.0
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubygems_version: 3.0.3
56
+ signing_key:
57
+ specification_version: 4
58
+ summary: Skip a command unless file(s) changed
59
+ test_files: []