flutter 0.1.0.pre.3 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bdffa233de57141c16bbbd41684ca85b04208b32edeec97625662383f4e3e753
4
- data.tar.gz: be3eb7f6bb1d0ffd8123ad4b8c2293ecdaf4c3979c75be8471542a2c26e1d771
3
+ metadata.gz: 2ca2f5eb98359bf0cbac8abbdedcbe6ca27ec7bf205625f44cf0c4150313eeb4
4
+ data.tar.gz: 6620320c3c54d63117ddc95550c0d4223411bfe9b6b469336fe9f60ffcddcfe3
5
5
  SHA512:
6
- metadata.gz: e301754a8492f5eaae1ba2388fe39c4d1fe2250b61bb7b792025d646e96719bd1df76a1ed8f669a821107e4e12f54b89c070671f5b86c29d24eae7bf2a3de3d7
7
- data.tar.gz: 4e69808a87b89d50f3d7fcf964ae3a2d5ccc176294e7f610e00d5ffb712131384ff24bb64e630e1ef1f5df1afac7f2175c986d031b4ada8dba9af37df00c930d
6
+ metadata.gz: 6f97e5720ea6fd890e4c6283a1193750eea3c1ffa64de2de550793cecb14f8636a205774a08811a3f4aea35ed5a764023603fa91a33bd0b4d00496925f4ab35c
7
+ data.tar.gz: 7f890be9219df6f89fde38e9bc34479a65c9a3d8d910ec1495732a2a32ac65d33291c507b8e7b6950facca0d02b6a47c726c864ae2abde9a4416ae983096b29c
data/CHANGELOG.md CHANGED
@@ -4,17 +4,27 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [Unreleased]
8
- ## [0.1.0.pre.3]
7
+ ## Unreleased
8
+ ## 0.2.0
9
9
  ### Added
10
- - Improved documentation for Tracker
11
- - Improved documentation for Persistance classes
10
+ - CI Recipe in README
11
+ - CI integration for incremental tests in branches/pull requests
12
+ - Release workflow tasks & github actions integration
13
+
14
+ ### Fixed
15
+ - Ensure all methods (including inherited ones) are considered when calculating signatures for a class or module.
16
+ - Fix calculation of total / filtered examples for rspec integration
17
+
18
+ ## 0.1.0.pre.3
19
+ ### Added
20
+ - Improved documentation for Persistence classes
21
+ - Improved documentation for Tracker
12
22
 
13
23
  ### Changed
14
- - Pinned dependencies to known working minimum versions
24
+ - Pinned dependencies to known working minimum versions
15
25
 
16
- ## [0.1.0.pre.2]
26
+ ## 0.1.0.pre.2
17
27
  ### Added
18
- - Minitest integration
19
- - RSpec integration
28
+ - Minitest integration
29
+ - RSpec integration
20
30
 
data/Gemfile CHANGED
@@ -11,6 +11,7 @@ group :test, :development do
11
11
  gem "overcommit", "~> 0.59.1"
12
12
  gem "gem-release", "~> 2.2"
13
13
  gem "guard", "~> 2.18"
14
+ gem "keepachangelog", "~> 0.6.1"
14
15
  gem "rubocop", "~> 1.21"
15
16
  gem "rubocop-shopify", require: false
16
17
  gem "rubocop-minitest", "~> 0.22.1"
data/README.md CHANGED
@@ -107,7 +107,55 @@ guard :rspec, cmd: "rspec" do
107
107
  end
108
108
  ```
109
109
  ## Configuring flutter in continuous integration
110
- **TODO**
110
+
111
+ Flutter can be used in continuous integration environments to speed up the turn
112
+ around time from running tests by only running tests affected by the changes
113
+ in a pull request.
114
+
115
+ ### Github Actions
116
+ The following example workflow with github actions does the following:
117
+ - Always run all tests on the `main` branch
118
+ - Only run tests affected by the "current" commit for CI workflows triggered by a `push` event on other branches
119
+ - If the CI workflow is triggered due to a `pull_request` event, run all tests affected by all commits in the branch
120
+ (by comparing against the branch point of the pull request)
121
+
122
+ ```yaml
123
+ # Get the commit where this branch diverges from origin/main
124
+ - name: Retrieve branch point
125
+ if: github.event_name == 'pull_request'
126
+ run: |
127
+ echo "::set-output name=KEY::$(diff -u <(git rev-list --first-parent origin/main) <(git rev-list --first-parent HEAD) | sed -ne 's/^ //p' | head -1)"
128
+ id: cache_keys
129
+ # Use the always-upload-cache action to:
130
+ # - Restore the flutter state from cache from either the branch point (if it was set in the previous step)
131
+ # or the last run in the current branch
132
+ # - After the run cache the flutter state using the current commit hash as the hash key
133
+ - name: Setup flutter state
134
+ id: flutter-state
135
+ uses: pat-s/always-upload-cache@v2.1.5
136
+ env:
137
+ cache-name: cache-flutter-state
138
+ with:
139
+ path: .flutter
140
+ key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ matrix.ruby-version }}-${{ github.sha }}
141
+ restore-keys: |
142
+ ${{ runner.os }}-build-${{ env.cache-name }}-${{ matrix.ruby-version }}-${{ steps.cache_keys.outputs.KEY }}
143
+ # If this is a push event on the main branch, clear the flutter state
144
+ # so that all tests are run and a full state is cached on the main branch
145
+ - name: Clear flutter state
146
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/heads/main')
147
+ run: rm -rf .flutter
148
+ ```
149
+ > **Note**
150
+ > The exact CI configuration would ofcourse depend on your workflow and confidence in selectively
151
+ > running tests for pull requests.
152
+
153
+ > **Warning**
154
+ > Selectively running tests in a pull request would show a drop in coverage if you are collecting
155
+ > and/or using code coverage as a "Check". One way to make Flutter work hand in hand with code
156
+ > coverage checks is to only validate that the diff in the pull request has a 100% coverage. For
157
+ > example with [codecov](https://docs.codecov.com/docs/commit-status#section-project-status) this can be
158
+ > achieved by only enabling the `project` status for the main branch and `patch` status otherwise.
111
159
 
112
160
  ## Related work
113
161
 
@@ -119,9 +167,19 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
119
167
 
120
168
  This project uses [overcommit](https://github.com/sds/overcommit) to enforce standards. Enable the precommit hooks in your local checkout by running: `overcommit --sign`
121
169
 
122
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number by running `gem bump`,
123
- then move the `Unreleased` entries in the [CHANGELOG](./CHANGELOG.md) to the new version and commit that.
124
- Finally tag and release the gem with `gem tag` and `gem release`
170
+ To install this gem onto your local machine, run `bundle exec rake install`.
171
+
172
+ ### Releasing a new version
173
+ - Ensure that the [Unreleased](./CHANGELOG.md#Unreleased) section of the changelog is up to date
174
+ and contains useful details.
175
+ - Create a new release using the `release` rake task as follows (for more details about specifying the version change
176
+ run `gem bump --help` which is the command used by the task):
177
+ - Patch release `bundle exec rake release["-v patch"]`
178
+ - Minor release `bundle exec rake release["-v minor"]`
179
+ - Major release `bundle exec rake release["-v major"]`
180
+ > **Note**
181
+ > The `release` rake task automates updating the changelog & version, committing the changes & creating a new tag
182
+ - Push the tag. The CI workflow for tag pushes will take care of publishing the gem & creating a github release.
125
183
 
126
184
  ## Contributing
127
185
 
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
4
3
  require "rake/testtask"
4
+ require "keepachangelog"
5
5
 
6
6
  Rake::TestTask.new(:unit) do |t|
7
7
  t.libs << "test"
@@ -22,3 +22,37 @@ RSpec::Core::RakeTask.new(:spec)
22
22
 
23
23
  task test: [:unit, :spec]
24
24
  task default: [:test, :spec, "rubocop:autocorrect_all"]
25
+
26
+ desc "Increment the version, update changelog and create a tag for the release"
27
+ task :release, [:version] do |_t, args|
28
+ parser = Keepachangelog::MarkdownParser.load("CHANGELOG.md")
29
+ log = parser.parsed_content["versions"].delete("Unreleased")
30
+ sh("gem bump --pretend #{args[:version]}") do |ok, _|
31
+ if ok
32
+ new_version = %x(gem bump --no-commit #{args[:version]} | awk '{print $4}' | uniq).chomp
33
+ parser.parsed_content["versions"]["Unreleased"] = { "url" => nil, "date" => nil, "changes" => {} }
34
+ parser.parsed_content["versions"][new_version] = log
35
+ File.open("CHANGELOG.md", "w") do |file|
36
+ file.write(parser.to_md)
37
+ end
38
+ %x(git add CHANGELOG.md lib/flutter/version.rb)
39
+ %x(git commit -m "Bump flutter to #{new_version}")
40
+ %x(gem tag -s)
41
+ Rake::Task["release_notes"].execute({ version: new_version })
42
+ end
43
+ end
44
+ end
45
+
46
+ desc "Get release notes for the current or specific version"
47
+ task :release_notes, [:version] do |_t, args|
48
+ version = (args[:version] || Flutter::VERSION)
49
+ parser = Keepachangelog::MarkdownParser.load("CHANGELOG.md")
50
+ parser.parsed_content.delete("intro")
51
+ parser.parsed_content.delete("title")
52
+ parser.parsed_content["versions"] = parser.parsed_content["versions"].select { |k, _v| k == version }
53
+ lines = parser.to_md.split("\n")
54
+ chunk = ["## #{version}"] + (
55
+ lines.slice_after { |line| line.include?("## #{version}") }.to_a[1] || []
56
+ )
57
+ puts chunk.join("\n")
58
+ end
data/codecov.yml ADDED
@@ -0,0 +1,13 @@
1
+ coverage:
2
+ status:
3
+ project:
4
+ default:
5
+ paths:
6
+ - "lib"
7
+ branches:
8
+ - main
9
+ patch:
10
+ default:
11
+ paths:
12
+ - "lib"
13
+ informational: false
@@ -10,7 +10,7 @@ end
10
10
  module Flutter
11
11
  module Minitest
12
12
  class << self
13
- attr_accessor :filtered
13
+ attr_accessor :filtered, :total
14
14
 
15
15
  def flutter_tracker
16
16
  @tracker ||= Flutter::Tracker.new(
@@ -31,7 +31,7 @@ module Flutter
31
31
  return unless ::Flutter.enabled
32
32
 
33
33
  Flutter::Minitest.flutter_tracker.persist!
34
- $stdout.puts "Flutter filtered out #{Flutter::Minitest.filtered} tests"
34
+ $stdout.puts "Flutter filtered #{Flutter::Minitest.filtered} / #{Flutter::Minitest.total} tests"
35
35
  if @verbose
36
36
  $stdout.puts "Persisted flutter #{Flutter::Minitest.flutter_tracker}"
37
37
  end
@@ -43,17 +43,15 @@ module Flutter
43
43
  module ClassMethods
44
44
  def runnable_methods
45
45
  Flutter::Minitest.filtered ||= 0
46
+ Flutter::Minitest.total ||= 0
46
47
  default = super()
48
+ Flutter::Minitest.total += default.length
47
49
  default.select do |test|
48
- skip = Minitest.flutter_tracker.skip?(
50
+ !Minitest.flutter_tracker.skip?(
49
51
  "#{name}##{test}",
50
52
  File.absolute_path(instance_method(test).source_location[0]),
51
53
  instance_method(test).source,
52
- )
53
- if skip
54
- Flutter::Minitest.filtered += 1
55
- end
56
- !skip
54
+ ).tap { |skip| Flutter::Minitest.filtered += 1 if skip }
57
55
  end
58
56
  end
59
57
  end
@@ -8,6 +8,11 @@ module Flutter
8
8
  class Parser
9
9
  attr_reader :signatures
10
10
 
11
+ @method_cache = {}
12
+ class << self
13
+ attr_reader :method_cache
14
+ end
15
+
11
16
  def initialize(file)
12
17
  @signatures = {}
13
18
  @targets = Set.new
@@ -49,23 +54,17 @@ module Flutter
49
54
  require_relative @file
50
55
  @targets.each do |container|
51
56
  instance = Kernel.const_get(container)
52
- class_methods = (
53
- instance.methods - Object.methods
54
- ) + (
55
- instance.private_methods - Object.private_methods
56
- )
57
- instance_methods = (
58
- instance.instance_methods - Object.instance_methods
59
- ) + (
60
- instance.private_instance_methods - Object.private_instance_methods
61
- )
57
+ class_methods = instance.methods + instance.private_methods
58
+ instance_methods = instance.instance_methods + instance.private_instance_methods
62
59
 
63
60
  @signatures.merge!(class_methods.map do |method|
64
- ["#{container}::#{method}", source_hash(instance.method(method))]
65
- end.to_h)
61
+ hash = source_hash(instance.method(method))
62
+ ["#{container}::#{method}", hash] if hash
63
+ end.compact.to_h)
66
64
  @signatures.merge!(instance_methods.map do |method|
67
- ["#{container}:#{method}", source_hash(instance.instance_method(method))]
68
- end.to_h)
65
+ hash = source_hash(instance.instance_method(method))
66
+ ["#{container}:#{method}", hash] if hash
67
+ end.compact.to_h)
69
68
  rescue NameError
70
69
  $stderr.puts "failed to load #{container} in #{@file}"
71
70
  end
@@ -74,9 +73,12 @@ module Flutter
74
73
  end
75
74
 
76
75
  def source_hash(callable)
77
- Digest::SHA1.hexdigest(callable.source)
76
+ return unless callable.source_location
77
+
78
+ sep = callable.is_a?(UnboundMethod) ? ":" : "::"
79
+ Parser.method_cache["#{callable.owner}#{sep}#{callable.name}"] ||= Digest::SHA1.hexdigest(callable.source)
78
80
  rescue MethodSource::SourceNotFoundError
79
- "<no-source>"
81
+ nil
80
82
  end
81
83
  end
82
84
  end
data/lib/flutter/rspec.rb CHANGED
@@ -5,7 +5,7 @@ require_relative "tracker"
5
5
  module Flutter
6
6
  module RSpec
7
7
  class << self
8
- attr_accessor :filtered
8
+ attr_accessor :filtered, :total
9
9
 
10
10
  def tracker
11
11
  @tracker ||= Flutter::Tracker.new(
@@ -17,20 +17,20 @@ module Flutter
17
17
 
18
18
  module ClassMethods
19
19
  def filtered_examples
20
- Flutter::RSpec.filtered ||= 0
20
+ Flutter::RSpec.filtered ||= Set.new
21
+ Flutter::RSpec.total ||= Set.new
21
22
  Flutter::RSpec.tracker.reset! if Flutter.enabled && Flutter.config.reset_storage
22
23
 
23
24
  original = super
25
+ Flutter::RSpec.total.merge(original)
24
26
  return original unless Flutter.enabled
25
27
 
26
28
  original.select do |example|
27
- skip = example.metadata[:block] && Flutter::RSpec.tracker.skip?(
29
+ !(example.metadata[:block] && Flutter::RSpec.tracker.skip?(
28
30
  example.full_description,
29
31
  example.metadata[:absolute_file_path],
30
32
  example.metadata[:block].source,
31
- )
32
- Flutter::RSpec.filtered += 1 if skip
33
- !skip
33
+ ).tap { |skip| Flutter::RSpec.filtered << example if skip })
34
34
  end
35
35
  end
36
36
  end
@@ -58,7 +58,7 @@ if defined?(RSpec.configure)
58
58
  config.after(:suite) do
59
59
  if Flutter.enabled
60
60
  $stdout.puts
61
- $stdout.puts "Flutter filtered out #{Flutter::RSpec.filtered} examples"
61
+ $stdout.puts "Flutter filtered #{Flutter::RSpec.filtered.length} / #{Flutter::RSpec.total.length} examples"
62
62
  Flutter::RSpec.tracker.persist!
63
63
  end
64
64
  end
@@ -98,6 +98,7 @@ module Flutter
98
98
  # that it was configured with
99
99
  # @return [void]
100
100
  def reset!
101
+ $stdout.puts "Resetting flutter: #{@storage}"
101
102
  @storage.clear!
102
103
  @source_mapping.clear
103
104
  @test_mapping.clear
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Flutter
4
- VERSION = "0.1.0.pre.3"
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flutter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.pre.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ali-Akber Saifee
8
8
  - Ankita Gupta
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-09-30 00:00:00.000000000 Z
12
+ date: 2022-10-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: deep_merge
@@ -73,6 +73,7 @@ files:
73
73
  - README.md
74
74
  - Rakefile
75
75
  - TODO.md
76
+ - codecov.yml
76
77
  - lib/flutter.rb
77
78
  - lib/flutter/config.rb
78
79
  - lib/flutter/minitest.rb
@@ -90,7 +91,7 @@ metadata:
90
91
  homepage_uri: https://github.com/indydevs/flutter
91
92
  source_code_uri: https://github.com/indydevs/flutter
92
93
  changelog_uri: https://github.com/indydevs/flutter/blob/master/CHANGELOG.md
93
- post_install_message:
94
+ post_install_message:
94
95
  rdoc_options: []
95
96
  require_paths:
96
97
  - lib
@@ -101,12 +102,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
101
102
  version: 2.7.0
102
103
  required_rubygems_version: !ruby/object:Gem::Requirement
103
104
  requirements:
104
- - - ">"
105
+ - - ">="
105
106
  - !ruby/object:Gem::Version
106
- version: 1.3.1
107
+ version: '0'
107
108
  requirements: []
108
- rubygems_version: 3.2.33
109
- signing_key:
109
+ rubygems_version: 3.3.7
110
+ signing_key:
110
111
  specification_version: 4
111
112
  summary: Intelligent test selection based on incremental code changes
112
113
  test_files: []