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 +4 -4
- data/CHANGELOG.md +18 -8
- data/Gemfile +1 -0
- data/README.md +62 -4
- data/Rakefile +35 -1
- data/codecov.yml +13 -0
- data/lib/flutter/minitest.rb +6 -8
- data/lib/flutter/parser.rb +18 -16
- data/lib/flutter/rspec.rb +7 -7
- data/lib/flutter/tracker.rb +1 -0
- data/lib/flutter/version.rb +1 -1
- metadata +9 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ca2f5eb98359bf0cbac8abbdedcbe6ca27ec7bf205625f44cf0c4150313eeb4
|
4
|
+
data.tar.gz: 6620320c3c54d63117ddc95550c0d4223411bfe9b6b469336fe9f60ffcddcfe3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
##
|
8
|
-
##
|
7
|
+
## Unreleased
|
8
|
+
## 0.2.0
|
9
9
|
### Added
|
10
|
-
|
11
|
-
|
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
|
-
|
24
|
+
- Pinned dependencies to known working minimum versions
|
15
25
|
|
16
|
-
##
|
26
|
+
## 0.1.0.pre.2
|
17
27
|
### Added
|
18
|
-
|
19
|
-
|
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
|
-
|
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`.
|
123
|
-
|
124
|
-
|
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
data/lib/flutter/minitest.rb
CHANGED
@@ -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
|
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
|
-
|
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
|
data/lib/flutter/parser.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
65
|
-
|
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
|
-
|
68
|
-
|
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
|
-
|
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
|
-
|
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 ||=
|
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
|
-
|
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
|
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
|
data/lib/flutter/tracker.rb
CHANGED
data/lib/flutter/version.rb
CHANGED
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.
|
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-
|
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:
|
107
|
+
version: '0'
|
107
108
|
requirements: []
|
108
|
-
rubygems_version: 3.
|
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: []
|