bashcov 1.8.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a36bdcb7d7aa907185855227615d085b989fdc7754f4bd5ebdb7d65736db3ff7
4
- data.tar.gz: 2bf28ebe2354264a91c926516584c091f008e5e11404d4b774c97dc01b3f8993
3
+ metadata.gz: dffc7667dad0e51e2e47f4c4df861d52be6240aff021c7c7771c2e4f8219f862
4
+ data.tar.gz: d720302f22dacf1ac91853301d65ac0a24ac3ff17415fa7fdb42fc1e6b906079
5
5
  SHA512:
6
- metadata.gz: fe32c995469459ad86f25991772b081613bb645a323fb279a5f2be9ffeb4ec6ced9601c07552654f28bfbd456473a23d04fc46741d7d0623dacde516956b05c7
7
- data.tar.gz: 4aca021b938322c850bfa17e63b542ff3acc0e8a22194d77b0cc527d26901d99b318a440a43041c6e47a4977eaf551be8b2d146f0b9a4a4f79781171140a94d2
6
+ metadata.gz: 284281285d8c60d800753fd0f4ff697d0a5e6faf246a64dfd1509f2cca4f3c6e0f5e91e417e76de2014937b91ada9fee4fcc266ad16dc8d1d106a3912cb6f524
7
+ data.tar.gz: cf79ef6c4e814d112c1255fe9fc59956537b7ad830eda345063395f5c7676895efcdbf7ec899185563e50577df756afb929bf6cb71b9106daeeef93d330dd5a9
data/.build.yml ADDED
@@ -0,0 +1,11 @@
1
+ image: archlinux
2
+ packages:
3
+ - ruby-bundler
4
+ - bash
5
+ sources:
6
+ - https://git.sr.ht/~infertux/bashcov
7
+ tasks:
8
+ - rake: |
9
+ cd bashcov
10
+ bundle install
11
+ bundle exec rake
@@ -0,0 +1,3 @@
1
+ github: infertux
2
+ liberapay: infertux
3
+ patreon: infertux
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.swp
2
+ *.gem
3
+ *.rbc
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ .rbx/
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
data/.gitlab-ci.yml ADDED
@@ -0,0 +1,57 @@
1
+ # Official language image. Look for the different tagged releases at:
2
+ # https://hub.docker.com/r/library/ruby/tags/
3
+ image: ruby:latest
4
+
5
+ before_script:
6
+ - ruby -v
7
+ - bundle install -j $(nproc)
8
+ - ./spec/install_bash.sh
9
+ - bash --version
10
+ - id
11
+ - env
12
+
13
+ audit:
14
+ script:
15
+ - bundle exec rake bundle:audit:update
16
+ - bundle exec rake bundle:audit:check
17
+
18
+ build:
19
+ script:
20
+ - bundle exec rake build
21
+ - bundle exec rake build:checksum
22
+ - cat checksums/*
23
+
24
+ cucumber:
25
+ script: bundle exec rake cucumber
26
+
27
+ # Current Bash versions can be found at https://git.savannah.gnu.org/cgit/bash.git
28
+ rspec-bash-5.2:
29
+ variables:
30
+ INSTALL_BASH_VERSION: "5.2"
31
+ script: bundle exec rake spec
32
+
33
+ rspec-bash-5.1:
34
+ variables:
35
+ INSTALL_BASH_VERSION: "5.1"
36
+ script: bundle exec rake spec
37
+
38
+ rspec-bash-5.0:
39
+ variables:
40
+ INSTALL_BASH_VERSION: "5.0"
41
+ script: bundle exec rake spec
42
+
43
+ rspec-bash-4.4:
44
+ variables:
45
+ INSTALL_BASH_VERSION: "4.4"
46
+ script: bundle exec rake spec
47
+
48
+ rspec-bash-4.3:
49
+ variables:
50
+ INSTALL_BASH_VERSION: "4.3"
51
+ script: bundle exec rake spec
52
+
53
+ rubocop:
54
+ script: bundle exec rake rubocop
55
+
56
+ yard:
57
+ script: bundle exec yard stats --list-undoc
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --format d
3
+ --order random
4
+ --profile
data/.rubocop.yml ADDED
@@ -0,0 +1,55 @@
1
+ require:
2
+ - rubocop-rake
3
+ - rubocop-rspec
4
+
5
+ AllCops:
6
+ TargetRubyVersion: 3.0
7
+ NewCops: enable
8
+
9
+ Metrics:
10
+ Enabled: false
11
+
12
+ Gemspec/DevelopmentDependencies:
13
+ Enabled: false
14
+
15
+ Layout/AccessModifierIndentation:
16
+ EnforcedStyle: outdent
17
+
18
+ Layout/LineLength:
19
+ Enabled: 100
20
+
21
+ Lint/RedundantSplatExpansion:
22
+ Enabled: false
23
+
24
+ RSpec/ExampleLength:
25
+ Enabled: false
26
+
27
+ RSpec/InstanceVariable:
28
+ Enabled: false
29
+
30
+ RSpec/MessageSpies:
31
+ EnforcedStyle: receive
32
+
33
+ RSpec/MultipleExpectations:
34
+ Enabled: false
35
+
36
+ RSpec/NamedSubject:
37
+ Enabled: false
38
+
39
+ RSpec/NestedGroups:
40
+ Enabled: false
41
+
42
+ Style/ParallelAssignment:
43
+ Enabled: false
44
+
45
+ Style/StringLiterals:
46
+ EnforcedStyle: double_quotes
47
+
48
+ Style/SpecialGlobalVars:
49
+ Enabled: false
50
+
51
+ Style/TrailingCommaInArrayLiteral:
52
+ EnforcedStyleForMultiline: comma
53
+
54
+ Style/TrailingCommaInHashLiteral:
55
+ EnforcedStyleForMultiline: comma
data/.simplecov ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ SimpleCov.start do
4
+ minimum_coverage 95
5
+ add_filter "/features/"
6
+ add_filter "/spec/"
7
+ add_filter "/tmp/"
8
+ add_filter "/.git/"
9
+ end
data/CHANGELOG.md CHANGED
@@ -1,7 +1,25 @@
1
- ## Unreleased ([changes](https://github.com/infertux/bashcov/compare/v1.8.2...master))
1
+ ## Unreleased ([changes](https://github.com/infertux/bashcov/compare/v3.0.0...master))
2
2
 
3
3
  * TBD
4
4
 
5
+ ## v3.0.0, 2023-04-10 ([changes](https://github.com/infertux/bashcov/compare/v1.8.2...v3.0.0))
6
+
7
+ * [MISC] New minimum Bash version supported is 4.3
8
+ * [MISC] New minimum Ruby version supported is 3.0
9
+ * [BUGFIX] Running Bashcov as root is now working (especially useful with Docker) although it is not recommended (#31, #43 and #56)
10
+ * [BUGFIX] Fix comments preceded by tabs not filtered out (#68)
11
+ * [BUGFIX] Fix two-line multilines not being treated as related (#67)
12
+ * [BUGFIX] Redefine `BASH_VERSION` when `bash_path` is read from command options (#57)
13
+ * [BUGFIX] Mute output from Bashcov and SimpleCov when requested (#54)
14
+ * [BUGFIX] Correctly handle empty scripts by short-circuiting
15
+ `FieldStream#each` if the reader stream is at end-of-file before
16
+ the start-of-fields pattern is encountered (#41)
17
+ * [FEATURE] Bashcov omits from the coverage results any files that match one
18
+ or more of the filters in `SimpleCov.filters` (#38)
19
+ * [FEATURE] Ensure that files matching the `SimpleCov.tracked_files` glob
20
+ pattern are included in the coverage results, regardless of
21
+ whether `Bashcov.skip_uncovered` is enabled (#38)
22
+
5
23
  ## v1.8.2, 2018-03-27 ([changes](https://github.com/infertux/bashcov/compare/v1.8.1...v1.8.2))
6
24
 
7
25
  * [BUGFIX] Fix coverage for complex heredoc constructions (#32)
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012-2018 Cédric Félizard
1
+ Copyright (c) 2012-2023 Cédric Félizard
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,146 +1,65 @@
1
1
  # Bashcov
2
2
 
3
+ [![Funding](https://img.shields.io/liberapay/patrons/infertux.svg?logo=liberapay)](https://liberapay.com/infertux/donate)
4
+ [![Sponsors](https://img.shields.io/liberapay/patrons/infertux)](https://liberapay.com/infertux)
3
5
  [![Gem Version](https://img.shields.io/gem/v/bashcov.svg)](https://rubygems.org/gems/bashcov)
4
- [![Build Status](https://secure.travis-ci.org/infertux/bashcov.png?branch=master)](https://travis-ci.org/infertux/bashcov)
5
- [![Coverage Status](https://coveralls.io/repos/infertux/bashcov/badge.png?branch=master)](https://coveralls.io/r/infertux/bashcov)
6
- [![Dependency Status](https://gemnasium.com/infertux/bashcov.png)](https://gemnasium.com/infertux/bashcov)
6
+ [![Build Status](https://gitlab.com/infertux/bashcov/badges/master/pipeline.svg)](https://gitlab.com/infertux/bashcov/-/pipelines)
7
7
  [![Maintainability](https://api.codeclimate.com/v1/badges/083fdbba795049cd5f06/maintainability)](https://codeclimate.com/github/infertux/bashcov/maintainability)
8
+ [![Inline docs](http://inch-ci.org/github/infertux/bashcov.svg)](http://inch-ci.org/github/infertux/bashcov)
8
9
 
9
- **Code coverage for Bash**
10
-
11
- * [Source Code]
12
- * [Bug Tracker]
13
- * [API Documentation]
14
- * [Changelog]
15
- * [Rubygem]
16
- * [Continuous Integration]
17
- * [Dependencies]
18
- * [SimpleCov]
19
-
20
- [Source Code]: https://github.com/infertux/bashcov "Source Code on Github"
21
- [Bug Tracker]: https://github.com/infertux/bashcov/issues "Bug Tracker on Github"
22
- [API documentation]: http://rubydoc.info/gems/bashcov/frames "API Documentation on Rubydoc"
23
- [Changelog]: https://github.com/infertux/bashcov/blob/master/CHANGELOG.md "Project Changelog"
24
- [Rubygem]: https://rubygems.org/gems/bashcov "Bashcov on Rubygems"
25
- [Continuous Integration]: https://travis-ci.org/infertux/bashcov "Bashcov on Travis-CI"
26
- [Dependencies]: https://gemnasium.com/infertux/bashcov "Bashcov dependencies on Gemnasium"
27
- [Bashcov]: https://github.com/infertux/bashcov
28
- [SimpleCov]: https://github.com/colszowka/simplecov "Bashcov is backed by SimpleCov to generate awesome coverage report"
29
- [Test app demo]: https://infertux.github.com/bashcov/test_app/ "Coverage for the bundled test application"
30
-
31
- You should check out these coverage examples - it's worth a thousand words:
32
-
33
- - [Test app demo]
34
- - [RVM demo](https://infertux.github.com/bashcov/rvm/ "Coverage for RVM")
10
+ Bashcov is a **code coverage analysis tool for Bash**.
11
+
12
+ In most cases, you'll want overall coverage results for your project from
13
+ [shUnit2](https://github.com/kward/shunit2),
14
+ [Bats](https://github.com/bats-core/bats-core),
15
+ [bash_unit](https://github.com/pgrange/bash_unit),
16
+ [assert.sh](https://github.com/lehmannro/assert.sh),
17
+ [bashaspec](https://github.com/d10n/bashaspec),
18
+ etc.
19
+ Bashcov automatically takes care of this by caching and merging results when generating reports,
20
+ so your report includes coverage across your test suites and thereby gives you a better picture of blank spots.
21
+
22
+ It uses the [SimpleCov](https://github.com/colszowka/simplecov) coverage library to generate HTML reports.
23
+ SimpleCov gets installed automatically when you install Bashcov.
24
+
25
+ Here are example coverages generated by Bashcov:
26
+ [test app demo](https://infertux.github.io/bashcov/test_app/ "Coverage for the bundled test application") &
27
+ [RVM demo](https://infertux.github.io/bashcov/rvm/ "Coverage for RVM").
35
28
 
36
29
  ## Installation
37
30
 
38
- `$ gem install bashcov`
31
+ `gem install bashcov`
32
+
33
+ If the `gem` command is unavailable, you need to [install Ruby](https://www.ruby-lang.org/en/documentation/installation/) first.
39
34
 
40
35
  ## Usage
41
36
 
42
- `$ bashcov --help` prints all available options.
43
- Here are some examples:
37
+ `bashcov --help` prints all available options. Here are some examples:
44
38
 
45
- $ bashcov ./script.sh
46
- $ bashcov --skip-uncovered ./script.sh
47
- $ bashcov -- ./script.sh --some --flags
48
- $ bashcov --skip-uncovered -- ./script.sh --some --flags
39
+ bashcov ./script.sh
40
+ bashcov --skip-uncovered ./script.sh
41
+ bashcov -- ./script.sh --some --flags
42
+ bashcov --skip-uncovered -- ./script.sh --some --flags
49
43
 
50
- `script.sh` can be a mere Bash script or typically your CI script.
51
- Bashcov will keep track of all executed scripts.
44
+ `./script.sh` can be a mere Bash script or typically your CI script. Bashcov will keep track of all executed scripts.
52
45
 
53
- Then it will create a directory named `./coverage/` containing nice HTML files.
54
- Open `./coverage/index.html` to browse the coverage report.
46
+ It will create a directory named `./coverage/`, you may open `./coverage/index.html` to browse the coverage report.
55
47
 
56
48
  ### SimpleCov integration
57
49
 
58
- You can take great advantage of [SimpleCov] by adding a `.simplecov` file in
59
- your project's root (like [this](https://github.com/infertux/bashcov/blob/master/spec/test_app/.simplecov)).
60
- See [SimpleCov README](https://github.com/colszowka/simplecov#readme) for more
61
- information.
62
-
63
- #### Controlling the command name
64
-
65
- Bashcov respects all of your `.simplecov` settings save one --
66
- [`SimpleCov.command_name`](http://www.rubydoc.info/gems/simplecov/SimpleCov/Configuration#command_name-instance_method),
67
- which is the tag that SimpleCov attaches to coverage results from a particular
68
- test suite. You can set the value of `SimpleCov.command_name` by using
69
- Bashcov's `--command-name` option, or by assigning a value to the environment
70
- variable `BASHCOV_COMMAND_NAME`. Otherwise, Bashcov will generate a command
71
- name for you based on the name of the currently-executing Bash script and any
72
- arguments passed to it. For example, assuming your Bash lives at `/bin/bash`
73
- and you run the command
74
-
75
- ```
76
- $ bashcov -- ./test_suite.sh --and some --flags
77
- ```
78
-
79
- Bashcov will set `SimpleCov.command_name` to `"/bin/bash ./test_suite.sh --and
80
- some --flags"`. Basing `SimpleCov.command_name` on the executing command helps
81
- to ensure that multiple coverage runs don't [overwrite each other's
82
- results](https://github.com/colszowka/simplecov#test-suite-names) due to
83
- SimpleCov identifying multiple runs by the same tag. The `--command-name` and
84
- `BASHCOV_COMMAND_NAME` knobs are there for you to twiddle in case your test
85
- suite runs the exact same `bashcov` command more than once, in which case the
86
- generated command name will not distinguish each invocation from the others.
87
-
88
- For more info on `SimpleCov.command_name` and its relation to SimpleCov's
89
- result-merging behavior, see the [SimpleCov
90
- README](https://github.com/colszowka/simplecov#merging-results).
91
-
92
- ### Some gory details
93
-
94
- Figuring out where an executing Bash script lives in the file system can be
95
- surprisingly difficult. Bash offers a fair amount of [introspection into its
96
- internals](https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html),
97
- but the location of the current script has to be inferred from the limited
98
- information available through `BASH_SOURCE`, `PWD`, and `OLDPWD` (and
99
- potentially `DIRSTACK` if you are using `pushd`/`popd`). For this purpose,
100
- Bashcov puts Bash in debug mode and sets up a `PS4` that expands the values of
101
- these variables, reading them on each command that Bash executes. But, given
102
- that:
103
-
104
- * `BASH_SOURCE` is only an absolute path if the script was invoked using an
105
- absolute path,
106
- * the builtins `cd`, `pushd`, and `popd` alter `PWD` and `OLDPWD`, and
107
- * none of these variables are read-only and can therefore be `unset` or
108
- otherwise altered,
109
-
110
- it can be easy to lose track of where we are.
111
-
112
- _"Wait a minute, what about `pwd`, `readlink`, and so on?"_ That would be great,
113
- except that subshells executed as part of expanding the `PS4` can cause Bash to
114
- report [extra executions](https://github.com/infertux/bashcov/commit/4130874e30a05b7ab6ea66fb96a19acaa973c178)
115
- for [certain lines](https://github.com/infertux/bashcov/pull/16). Also,
116
- subshells are slow as the `PS4` is expanded on each and every command when Bash
117
- is in debug mode.
118
-
119
- To deal with these limitations, Bashcov uses the expedient of maintaining two
120
- stacks that track changes to `PWD` and `OLDPWD`. To determine the full path to
121
- the executing script, Bashcov iterates in reverse over the `PWD` stack, testing
122
- for the first `$PWD/$BASH_SOURCE` combination that refers to an existing file.
123
- This heuristic is susceptible to false positives -- under certain combinations
124
- of directory structure, script invocation paths, and working directory changes,
125
- it may yield a path that doesn't refer to the currently-running script.
126
- However, it performs well under the various working directory changes performed
127
- in the [test app demo] and avoids the spurious extra hits caused by using
128
- subshells in the `PS4`.
129
-
130
- One final note on innards: Bash 4.3 fixed a bug in which `PS4` expansion is
131
- truncated to a maximum of 128 characters. On platforms whose Bash version
132
- suffers from this bug, Bashcov uses the ASCII record separator character to
133
- delimit the `PS4` fields, whereas it uses a long random string on Bash 4.3 and
134
- above. When the field delimiter appears in the path of a script under test or
135
- in a command the script executes, Bashcov won't correctly parse the `PS4` and
136
- will abort early with incomplete coverage results.
50
+ You can leverage the underlying library [SimpleCov](https://github.com/colszowka/simplecov)
51
+ by adding a `.simplecov` file in your project's root, like [this](https://github.com/infertux/bashcov/blob/master/spec/test_app/.simplecov).
52
+ See [advanced usage](./USAGE.md) for more information.
137
53
 
138
54
  ## Contributing
139
55
 
140
56
  Bug reports and patches are most welcome.
141
57
  See the [contribution guidelines](https://github.com/infertux/bashcov/blob/master/CONTRIBUTING.md).
142
58
 
59
+ ## Sponsorship
60
+
61
+ Bashcov was [created in 2012](https://github.com/infertux/bashcov/commit/f65e65e5aa3377beb334beee9924136a34a913e8) and it needs your help. I have been maintaining the project for over a decade and keeping it working with new releases of Bash and Ruby takes time. If you use Bashcov professionally, please considerer supporting it on [Liberapay](https://liberapay.com/infertux) through your employer or directly. Thank you for supporting *Free and Open-Source Software*.
62
+
143
63
  ## License
144
64
 
145
65
  MIT
146
-
data/Rakefile CHANGED
@@ -2,8 +2,13 @@
2
2
 
3
3
  require "bundler/gem_tasks"
4
4
 
5
+ require "bundler/audit/task"
6
+ Bundler::Audit::Task.new
7
+
5
8
  require "cucumber/rake/task"
6
- Cucumber::Rake::Task.new
9
+ Cucumber::Rake::Task.new do |t|
10
+ t.cucumber_opts = %w[--publish-quiet]
11
+ end
7
12
 
8
13
  require "rspec/core/rake_task"
9
14
  RSpec::Core::RakeTask.new(:spec) do |t|
@@ -13,4 +18,4 @@ end
13
18
  require "rubocop/rake_task"
14
19
  RuboCop::RakeTask.new
15
20
 
16
- task default: %i[rubocop spec cucumber]
21
+ task default: %i[bundle:audit cucumber spec rubocop]
data/TESTING.md ADDED
@@ -0,0 +1,4 @@
1
+ `bundle exec rake` will run a quick test suite with the current Bash and Ruby version.
2
+
3
+ `./test.sh` will run all [GitLab CI pipelines](https://gitlab.com/infertux/bashcov/-/pipelines) locally.
4
+ You'll need [Docker](https://www.docker.com/) and [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner) installed on your machine.
data/USAGE.md ADDED
@@ -0,0 +1,66 @@
1
+ ### Controlling the command name
2
+
3
+ Bashcov respects all of your `.simplecov` settings save one --
4
+ [`SimpleCov.command_name`](http://www.rubydoc.info/gems/simplecov/SimpleCov/Configuration#command_name-instance_method),
5
+ which is the tag that SimpleCov attaches to coverage results from a particular
6
+ test suite. You can set the value of `SimpleCov.command_name` by using
7
+ Bashcov's `--command-name` option, or by assigning a value to the environment
8
+ variable `BASHCOV_COMMAND_NAME`. Otherwise, Bashcov will generate a command
9
+ name for you based on the name of the currently-executing Bash script and any
10
+ arguments passed to it. For example, assuming your Bash lives at `/bin/bash`
11
+ and you run the command
12
+
13
+ ```
14
+ bashcov -- ./test_suite.sh --and some --flags
15
+ ```
16
+
17
+ Bashcov will set `SimpleCov.command_name` to `"/bin/bash ./test_suite.sh --and
18
+ some --flags"`. Basing `SimpleCov.command_name` on the executing command helps
19
+ to ensure that multiple coverage runs don't [overwrite each other's
20
+ results](https://github.com/colszowka/simplecov#test-suite-names) due to
21
+ SimpleCov identifying multiple runs by the same tag. The `--command-name` and
22
+ `BASHCOV_COMMAND_NAME` knobs are there for you to twiddle in case your test
23
+ suite runs the exact same `bashcov` command more than once, in which case the
24
+ generated command name will not distinguish each invocation from the others.
25
+
26
+ For more info on `SimpleCov.command_name` and its relation to SimpleCov's
27
+ result-merging behavior, see the [SimpleCov
28
+ README](https://github.com/colszowka/simplecov#merging-results).
29
+
30
+ ### Some gory details
31
+
32
+ Figuring out where an executing Bash script lives in the file system can be
33
+ surprisingly difficult. Bash offers a fair amount of [introspection into its
34
+ internals](https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html),
35
+ but the location of the current script has to be inferred from the limited
36
+ information available through `BASH_SOURCE`, `PWD`, and `OLDPWD` (and
37
+ potentially `DIRSTACK` if you are using `pushd`/`popd`). For this purpose,
38
+ Bashcov puts Bash in debug mode and sets up a `PS4` that expands the values of
39
+ these variables, reading them on each command that Bash executes. But, given
40
+ that:
41
+
42
+ * `BASH_SOURCE` is only an absolute path if the script was invoked using an
43
+ absolute path,
44
+ * the builtins `cd`, `pushd`, and `popd` alter `PWD` and `OLDPWD`, and
45
+ * none of these variables are read-only and can therefore be `unset` or
46
+ otherwise altered,
47
+
48
+ it can be easy to lose track of where we are.
49
+
50
+ _"Wait a minute, what about `pwd`, `readlink`, and so on?"_ That would be great,
51
+ except that subshells executed as part of expanding the `PS4` can cause Bash to
52
+ report [extra executions](https://github.com/infertux/bashcov/commit/4130874e30a05b7ab6ea66fb96a19acaa973c178)
53
+ for [certain lines](https://github.com/infertux/bashcov/pull/16). Also,
54
+ subshells are slow as the `PS4` is expanded on each and every command when Bash
55
+ is in debug mode.
56
+
57
+ To deal with these limitations, Bashcov uses the expedient of maintaining two
58
+ stacks that track changes to `PWD` and `OLDPWD`. To determine the full path to
59
+ the executing script, Bashcov iterates in reverse over the `PWD` stack, testing
60
+ for the first `$PWD/$BASH_SOURCE` combination that refers to an existing file.
61
+ This heuristic is susceptible to false positives -- under certain combinations
62
+ of directory structure, script invocation paths, and working directory changes,
63
+ it may yield a path that doesn't refer to the currently-running script.
64
+ However, it performs well under the various working directory changes performed
65
+ in the [test app demo] and avoids the spurious extra hits caused by using
66
+ subshells in the `PS4`.
data/bashcov.gemspec CHANGED
@@ -1,36 +1,42 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path("../lib", __FILE__)
4
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require "bashcov/version"
3
+ require_relative "lib/bashcov/version"
6
4
 
7
- Gem::Specification.new do |gem|
8
- gem.name = "bashcov"
9
- gem.version = Bashcov::VERSION
10
- gem.authors = ["Cédric Félizard"]
11
- gem.email = ["cedric@felizard.fr"]
12
- gem.description = "Code coverage tool for Bash"
13
- gem.summary = gem.description
14
- gem.homepage = "https://github.com/infertux/bashcov"
15
- gem.license = "MIT"
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "bashcov"
7
+ spec.version = Bashcov::VERSION
8
+ spec.authors = ["Cédric Félizard"]
9
+ spec.email = ["cedric@felizard.fr"]
16
10
 
17
- gem.files = `git ls-files -z`.split("\x0").reject do |file|
18
- file.start_with?(".") || file.match(%r{\A(test|spec|features)/})
19
- end
11
+ spec.summary = spec.description
12
+ spec.description = "Code coverage tool for Bash"
13
+ spec.homepage = "https://github.com/infertux/bashcov"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 3.0.0"
20
16
 
21
- gem.executables = gem.files.grep(%r{\Abin/}).map { |f| File.basename(f) }
22
- gem.require_paths = ["lib"]
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://github.com/infertux/bashcov"
19
+ spec.metadata["changelog_uri"] = "https://github.com/infertux/bashcov/blob/master/CHANGELOG.md"
23
20
 
24
- gem.required_ruby_version = ">= 2.3.0"
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
25
29
 
26
- gem.add_dependency "simplecov", "0.15.1"
30
+ spec.add_dependency "simplecov", "~> 0.21.2"
27
31
 
28
- gem.add_development_dependency "aruba", "~> 0.14.3"
29
- gem.add_development_dependency "coveralls"
30
- gem.add_development_dependency "cucumber"
31
- gem.add_development_dependency "mutant-rspec"
32
- gem.add_development_dependency "rake"
33
- gem.add_development_dependency "rspec"
34
- gem.add_development_dependency "rubocop"
35
- gem.add_development_dependency "yard"
32
+ spec.add_development_dependency "aruba"
33
+ spec.add_development_dependency "bundler-audit"
34
+ spec.add_development_dependency "cucumber"
35
+ spec.add_development_dependency "rake"
36
+ spec.add_development_dependency "rspec"
37
+ spec.add_development_dependency "rubocop"
38
+ spec.add_development_dependency "rubocop-rake"
39
+ spec.add_development_dependency "rubocop-rspec"
40
+ spec.add_development_dependency "yard"
41
+ spec.metadata["rubygems_mfa_required"] = "true"
36
42
  end
data/bin/bashcov CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- lib = File.expand_path("../../lib", __FILE__)
4
+ lib = File.expand_path("../lib", __dir__)
5
5
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
6
 
7
7
  require "bashcov"
@@ -26,8 +26,18 @@ if SimpleCov.use_merging
26
26
  end
27
27
 
28
28
  SimpleCov.at_exit do
29
- puts "Run completed using #{Bashcov.fullname}"
30
- result.format!
29
+ puts "Run completed using #{Bashcov.fullname}" unless Bashcov.mute
30
+
31
+ begin
32
+ # XXX: suppress output from https://github.com/colszowka/simplecov-html/blob/9ec41504ab139fabfaddfc786dfdab5d6aca0bab/lib/simplecov-html.rb#L25
33
+ # See https://github.com/infertux/bashcov/issues/53
34
+ original_stdout = $stdout
35
+ $stdout = StringIO.new if Bashcov.mute
36
+
37
+ result.format!
38
+ ensure
39
+ $stdout = original_stdout
40
+ end
31
41
  end
32
42
 
33
43
  exit status.exitstatus
@@ -34,7 +34,7 @@ module Bashcov
34
34
  return false unless File.exist?(filename) && File.readable?(filename) \
35
35
  && File.file?(File.realpath(filename))
36
36
 
37
- shellscript_shebang?(filename) || \
37
+ shellscript_shebang?(filename) ||
38
38
  (shellscript_extension?(filename) && shellscript_syntax?(filename))
39
39
  end
40
40
 
@@ -54,10 +54,10 @@ module Bashcov
54
54
 
55
55
  return false unless shebang[0..1] == "#!"
56
56
 
57
- shell, arg = shebang[2..-1].split(/\s+/, 2)
57
+ shell, arg = shebang[2..].split(/\s+/, 2)
58
58
  shell_basename = File.basename(shell)
59
59
 
60
- SHELL_BASENAMES.include?(shell_basename) || \
60
+ SHELL_BASENAMES.include?(shell_basename) ||
61
61
  (OTHER_BASENAMES.include?(shell_basename) && SHELL_BASENAMES.include?(arg))
62
62
  end
63
63
 
@@ -23,7 +23,7 @@ module Bashcov
23
23
  end
24
24
  end
25
25
 
26
- # Yields fields extracted from a input stream
26
+ # Yields fields extracted from an input stream
27
27
  # @param [String, nil] delimiter the field separator
28
28
  # @param [Integer] field_count the number of fields to extract
29
29
  # @param [Regexp] start_match a +Regexp+ that, when matched against the
@@ -33,39 +33,51 @@ module Bashcov
33
33
  # +start_match+ is matched with fewer than +field_count+ fields yielded
34
34
  # since the last match, yields empty strings until +field_count+ is
35
35
  # reached.
36
- def each(delimiter, field_count, start_match)
36
+ def each(delimiter, field_count, start_match, &block)
37
37
  return enum_for(__method__, delimiter, field_count, start_match) unless block_given?
38
38
 
39
- # The number of fields processed since passing the last start-of-fields
40
- # match
41
- seen_fields = 0
39
+ chunked = each_field(delimiter).chunk(&chunk_matches(start_match))
42
40
 
43
- fields = each_field(delimiter)
41
+ yield_fields = lambda do |(_, chunk)|
42
+ chunk.each(&block)
43
+ (field_count - chunk.size).times { yield "" }
44
+ end
45
+
46
+ # Skip junk that might appear before the first start-of-fields match
47
+ begin
48
+ n, chunk = chunked.next
49
+ yield_fields.call([n, chunk]) unless n.zero?
50
+ rescue StopIteration
51
+ return
52
+ end
44
53
 
45
- # Close over +field_count+ and +seen_fields+ to yield empty strings to
46
- # the caller when we've already hit the next start-of-fields match
47
- yield_remaining = -> { (field_count - seen_fields).times { yield "" } }
54
+ chunked.each(&yield_fields)
55
+ end
48
56
 
49
- # Advance until the first start-of-fields match
50
- loop { break if fields.next =~ start_match }
57
+ private
51
58
 
52
- fields.each do |field|
53
- # If the current field is the start-of-fields match...
54
- if field =~ start_match
55
- # Fill out any remaining (unparseable) fields with empty strings
56
- yield_remaining.call
59
+ # @param [Regexp] start_match a +Regexp+ that, when matched against the
60
+ # input stream, signifies the beginning of the next series of fields to
61
+ # yield
62
+ # @return [Proc] a unary +Proc+ that returns +nil+ if the argument mathes
63
+ # the +start_match+ +Regexp+, and otherwise returns the number of
64
+ # start-of-fields signifiers so far encountered.
65
+ # @example
66
+ # chunker = chunk_matches /<=>/
67
+ # chunked = %w[foo fighters <=> bar none <=> baz luhrmann].chunk(&chunker)
68
+ # chunked.to_a
69
+ # #=> [[0, ["foo", "fighters"]], [1, ["bar", "none"]], [2, ["baz", "luhrmann"]]]
70
+ def chunk_matches(start_match)
71
+ i = 0
57
72
 
58
- seen_fields = 0
59
- elsif seen_fields < field_count
60
- yield field
61
- seen_fields += 1
73
+ lambda do |e|
74
+ if e.match?(start_match)
75
+ i += 1
76
+ nil
77
+ else
78
+ i
62
79
  end
63
80
  end
64
-
65
- # One last filling-out of empty fields if we're at the end of the stream
66
- yield_remaining.call
67
-
68
- read.close unless read.closed?
69
81
  end
70
82
  end
71
83
  end
data/lib/bashcov/lexer.rb CHANGED
@@ -27,8 +27,8 @@ module Bashcov
27
27
 
28
28
  # Process and complete initial coverage.
29
29
  # @return [void]
30
- def complete_coverage # rubocop:disable Metrics/MethodLength
31
- lines = IO.read(@filename).encode("utf-8", invalid: :replace).lines
30
+ def complete_coverage
31
+ lines = File.read(@filename).encode("utf-8", invalid: :replace).lines
32
32
 
33
33
  lines.each_with_index do |line, lineno|
34
34
  # multi-line arrays
@@ -72,7 +72,7 @@ module Bashcov
72
72
  private
73
73
 
74
74
  def mark_multiline(lines, lineno, regexp, forward: true)
75
- seek_forward = lines[lineno..-1].join
75
+ seek_forward = lines[lineno..].join
76
76
  return unless (multiline_match = seek_forward.match(regexp))
77
77
 
78
78
  length = multiline_match.to_s.count($/)
@@ -81,7 +81,7 @@ module Bashcov
81
81
  reference_lineno = (forward ? first - 1 : last)
82
82
 
83
83
  # don't seek backward if first line is already covered
84
- return if !forward && @coverage[first]
84
+ return if !forward && @coverage[first - 1]
85
85
 
86
86
  range.each do |sub_lineno|
87
87
  # mark related lines with the same coverage as the reference line
@@ -95,8 +95,8 @@ module Bashcov
95
95
  @coverage[lineno] = Bashcov::Line::UNCOVERED if relevant?(line)
96
96
  end
97
97
 
98
- def relevant?(line) # rubocop:disable Metrics/CyclomaticComplexity
99
- line.sub!(/ #.*\Z/, "") # remove comments
98
+ def relevant?(line)
99
+ line.sub!(/\s#.*\Z/, "") # remove comments
100
100
  line.strip!
101
101
 
102
102
  relevant = true
@@ -107,7 +107,7 @@ module Bashcov
107
107
  line.end_with?(*IGNORE_END_WITH)
108
108
 
109
109
  relevant &= false if line =~ /\A\w+\(\)/ # function declared without the `function` keyword
110
- relevant &= false if line =~ /\A[^\)]+\)\Z/ # case statement selector, e.g. `--help)`
110
+ relevant &= false if line =~ /\A[^)]+\)\Z/ # case statement selector, e.g. `--help)`
111
111
 
112
112
  relevant
113
113
  end
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "tempfile"
4
+
5
+ require "simplecov"
6
+
3
7
  require "bashcov/detective"
4
8
  require "bashcov/errors"
5
9
  require "bashcov/field_stream"
@@ -18,23 +22,40 @@ module Bashcov
18
22
  # Runs the command with appropriate xtrace settings.
19
23
  # @note Binds Bashcov +stdin+ to the program being executed.
20
24
  # @return [Process::Status] Status of the executed command
21
- def run # rubocop:disable Metrics/MethodLength
25
+ def run
22
26
  # Clear out previous run
23
27
  @result = nil
24
28
 
25
29
  field_stream = FieldStream.new
26
30
  @xtrace = Xtrace.new(field_stream)
27
-
28
31
  fd = @xtrace.file_descriptor
29
- env = { "PS4" => Xtrace.ps4 }
32
+
30
33
  options = { in: :in }
34
+ options[fd] = fd # bind FDs to the child process
31
35
 
32
36
  if Bashcov.options.mute
33
37
  options[:out] = "/dev/null"
34
38
  options[:err] = "/dev/null"
35
39
  end
36
40
 
37
- run_xtrace(fd, env, options) do
41
+ env =
42
+ if Process.uid.zero?
43
+ # if running as root, Bash 4.4+ does not inherit $PS4 from the environment
44
+ # https://github.com/infertux/bashcov/issues/43#issuecomment-450605839
45
+ write_warning "running as root is NOT recommended, Bashcov may not work properly."
46
+
47
+ temp_file = Tempfile.new("bashcov_bash_env")
48
+ temp_file.write("export PS4='#{Xtrace.ps4}'\n")
49
+ temp_file.close
50
+
51
+ { "BASH_ENV" => temp_file.path }
52
+ else
53
+ { "PS4" => Xtrace.ps4 }
54
+ end
55
+
56
+ env["BASH_XTRACEFD"] = fd.to_s
57
+
58
+ with_xtrace_flag do
38
59
  command_pid = Process.spawn env, *@command, options # spawn the command
39
60
 
40
61
  begin
@@ -58,6 +79,8 @@ module Bashcov
58
79
  end
59
80
  end
60
81
 
82
+ temp_file&.unlink
83
+
61
84
  $?
62
85
  end
63
86
 
@@ -83,39 +106,13 @@ module Bashcov
83
106
  ].join
84
107
  end
85
108
 
86
- def run_xtrace(fd, env, options)
87
- # Older versions of Bash (< 4.1) don't have the BASH_XTRACEFD variable
88
- if Bashcov.bash_xtracefd?
89
- options[fd] = fd # bind FDs to the child process
90
-
91
- env["BASH_XTRACEFD"] = fd.to_s
92
- else
93
- # Send subprocess standard error to @xtrace.file_descriptor
94
- options[:err] = fd
95
-
96
- # Don't bother issuing warning if we're silencing output anyway
97
- unless Bashcov.mute
98
- write_warning <<-WARNING
99
- you are using a version of Bash that does not support
100
- BASH_XTRACEFD. All xtrace output will print to standard error, and
101
- your script's output on standard error will not be printed to the
102
- console.
103
- WARNING
104
- end
105
- end
106
-
107
- with_xtrace_flag do
108
- yield
109
- end
110
- end
111
-
112
109
  # @note +SHELLOPTS+ must be exported so we use Ruby's {ENV} variable
113
110
  # @yield [void] adds "xtrace" to +SHELLOPTS+ and then runs the provided
114
111
  # block
115
112
  # @return [Object, ...] the value returned by the calling block
116
113
  def with_xtrace_flag
117
- existing_flags_s = ENV["SHELLOPTS"]
118
- existing_flags = (existing_flags_s || "").split(":")
114
+ existing_flags_s = ENV.fetch("SHELLOPTS", "")
115
+ existing_flags = existing_flags_s.split(":")
119
116
  ENV["SHELLOPTS"] = (existing_flags | ["xtrace"]).join(":")
120
117
 
121
118
  yield
@@ -126,25 +123,49 @@ module Bashcov
126
123
  # Add files which have not been executed at all (i.e. with no coverage)
127
124
  # @return [void]
128
125
  def find_bash_files!
129
- return if Bashcov.skip_uncovered
126
+ filtered_files.each do |filename|
127
+ @coverage[filename] = [] if !@coverage.include?(filename) && @detective.shellscript?(filename)
128
+ end
129
+ end
130
130
 
131
- Pathname.new(Bashcov.root_directory).find do |filename|
132
- if !@coverage.include?(filename) && @detective.shellscript?(filename)
133
- @coverage[filename] = []
134
- end
131
+ # @return [Array<Pathname>] the list of files that should be included in
132
+ # coverage results, unless filtered by one or more SimpleCov filters
133
+ def tracked_files
134
+ return @tracked_files if defined? @tracked_files
135
+
136
+ mandatory = SimpleCov.tracked_files ? Pathname.glob(SimpleCov.tracked_files) : []
137
+ under_root = Bashcov.skip_uncovered ? [] : Pathname.new(Bashcov.root_directory).find.to_a
138
+
139
+ @tracked_files = (mandatory + under_root).uniq
140
+ end
141
+
142
+ # @return [Array<Pathname>] the list of files that should be included in
143
+ # coverage results
144
+ def filtered_files
145
+ return @filtered_files if defined? @filtered_files
146
+
147
+ source_files = tracked_files.map do |file|
148
+ SimpleCov::SourceFile.new(file.to_s, @coverage.fetch(file, []))
149
+ end
150
+
151
+ source_file_to_tracked_file = source_files.zip(tracked_files).to_h
152
+
153
+ @filtered_files = SimpleCov.filtered(source_files).map do |source_file|
154
+ source_file_to_tracked_file[source_file]
135
155
  end
136
156
  end
137
157
 
138
158
  # @return [void]
139
159
  def expunge_invalid_files!
140
160
  @coverage.each_key do |filename|
141
- next if filename.file?
161
+ if !filename.file?
162
+ @coverage.delete filename
163
+ write_warning "#{filename} was executed but has been deleted since then - it won't be reported in coverage."
142
164
 
143
- @coverage.delete filename
144
- write_warning <<-WARNING
145
- #{filename} was executed but has been deleted since then - it won't
146
- be reported in coverage.
147
- WARNING
165
+ elsif !@detective.shellscript?(filename)
166
+ @coverage.delete filename
167
+ write_warning "#{filename} was partially executed but has invalid Bash syntax - it won't be reported in coverage."
168
+ end
148
169
  end
149
170
  end
150
171
 
@@ -158,7 +179,7 @@ module Bashcov
158
179
  end
159
180
 
160
181
  def convert_coverage
161
- Hash[@coverage.map { |filename, coverage| [filename.to_s, coverage] }]
182
+ @coverage.transform_keys(&:to_s)
162
183
  end
163
184
  end
164
185
  end
@@ -3,5 +3,5 @@
3
3
  # :nodoc:
4
4
  module Bashcov
5
5
  # Current Bashcov version
6
- VERSION = "1.8.2"
6
+ VERSION = "3.0.0"
7
7
  end
@@ -24,11 +24,10 @@ module Bashcov
24
24
  class << self
25
25
  attr_writer :delimiter, :ps4
26
26
 
27
- # [String] A randomly-generated UUID or the ASCII RS (record separator)
28
- # character, depending on whether the current Bash suffers from the
29
- # truncated +PS4+ bug. Used for delimiting the fields of the +PS4+.
27
+ # [String] A randomly-generated UUID used for delimiting the fields of
28
+ # the +PS4+.
30
29
  def delimiter
31
- @delimiter ||= Bashcov.truncated_ps4? ? "\x1E" : SecureRandom.uuid
30
+ @delimiter ||= SecureRandom.uuid
32
31
  end
33
32
 
34
33
  # @return [String] +PS4+ variable used for xtrace output. Expands to
@@ -93,9 +92,12 @@ module Bashcov
93
92
  # play nicely with +Enumerator+s backed by +IO+ objects.
94
93
  loop do
95
94
  break if (hit = (1..field_count).map { fields.next }).empty?
95
+
96
96
  parse_hit!(*hit)
97
97
  end
98
98
 
99
+ @read.close unless @read.closed?
100
+
99
101
  @files
100
102
  end
101
103
 
@@ -115,8 +117,11 @@ module Bashcov
115
117
  # If +LINENO+ isn't a series of digits, something has gone wrong. Add
116
118
  # +@files+ to the exception in order to propagate the existing coverage
117
119
  # data back to the {Bashcov::Runner} instance.
118
- if lineno =~ /\A\d+\z/
120
+ if /\A\d+\z/.match?(lineno)
119
121
  lineno = lineno.to_i
122
+ elsif lineno == "${LINENO-}"
123
+ # the variable doesn't expand on line misses so we can safely ignore it
124
+ return
120
125
  else
121
126
  raise XtraceError.new(
122
127
  "expected integer for LINENO, got #{lineno.inspect}", @files
data/lib/bashcov.rb CHANGED
@@ -3,15 +3,12 @@
3
3
  require "optparse"
4
4
  require "pathname"
5
5
 
6
- require "bashcov/bash_info"
7
6
  require "bashcov/runner"
8
7
  require "bashcov/version"
9
8
 
10
9
  # Bashcov default module
11
10
  # @note Keep it short!
12
11
  module Bashcov
13
- extend Bashcov::BashInfo
14
-
15
12
  # A +Struct+ to store Bashcov configuration
16
13
  Options = Struct.new(
17
14
  *%i[skip_uncovered mute bash_path root_directory command command_name]
@@ -55,8 +52,9 @@ module Bashcov
55
52
  VERSION,
56
53
  "with Bash #{BASH_VERSION},",
57
54
  "Ruby #{RUBY_VERSION},",
58
- "and SimpleCov #{SimpleCov::VERSION}.",
59
- ].join(" ")
55
+ "and SimpleCov #{SimpleCov::VERSION}",
56
+ (Process.uid.zero? ? " as root user (NOT recommended)" : nil),
57
+ ].compact.join(" ")
60
58
  end
61
59
 
62
60
  # @return [String] The value to use as +SimpleCov.command_name+. Uses the
@@ -65,17 +63,35 @@ module Bashcov
65
63
  # representation of {Bashcov#command}.
66
64
  def command_name
67
65
  return @options.command_name if @options.command_name
68
- return ENV["BASHCOV_COMMAND_NAME"] unless ENV.fetch("BASHCOV_COMMAND_NAME", "").empty?
66
+ return ENV.fetch("BASHCOV_COMMAND_NAME", nil) unless ENV.fetch("BASHCOV_COMMAND_NAME", "").empty?
67
+
69
68
  command.compact.join(" ")
70
69
  end
71
70
 
71
+ def bash_path
72
+ # First attempt to use the value from `options`, but ignore all exceptions.
73
+ # This is used early for the `BASH_VERSION` definition, so first use will likely error.
74
+ begin
75
+ return @options.bash_path if @options.bash_path
76
+ rescue NoMethodError; end # rubocop:disable Lint/SuppressedException
77
+
78
+ # Support the same `BASHCOV_BASH_PATH` environment variable used in the spec tests.
79
+ return ENV.fetch("BASHCOV_BASH_PATH", nil) unless ENV.fetch("BASHCOV_BASH_PATH", "").empty?
80
+
81
+ # Fall back to standard Bash location.
82
+ "/bin/bash"
83
+ end
84
+
85
+ def bash_version
86
+ `#{bash_path} -c 'echo -n ${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}'`
87
+ end
88
+
72
89
  # Wipe the current options and reset default values
73
90
  def set_default_options!
74
91
  @options = Options.new
75
92
 
76
93
  @options.skip_uncovered = false
77
94
  @options.mute = false
78
- @options.bash_path = "/bin/bash"
79
95
  @options.root_directory = Dir.getwd
80
96
  end
81
97
 
@@ -103,8 +119,8 @@ module Bashcov
103
119
  HELP
104
120
  end
105
121
 
106
- def option_parser # rubocop:disable Metrics/MethodLength
107
- OptionParser.new do |opts| # rubocop:disable Metrics/BlockLength
122
+ def option_parser
123
+ OptionParser.new do |opts|
108
124
  opts.program_name = program_name
109
125
  opts.version = Bashcov::VERSION
110
126
  opts.banner = help
@@ -119,10 +135,17 @@ module Bashcov
119
135
  end
120
136
  opts.on("--bash-path PATH", "Path to Bash executable") do |p|
121
137
  raise Errno::ENOENT, p unless File.file? p
138
+
122
139
  options.bash_path = p
140
+
141
+ # Redefine `BASH_VERSION` constant with upated `bash_path`.
142
+ # This is hacky, but a lot of code references that constant and this should only have to be done once.
143
+ send(:remove_const, "BASH_VERSION")
144
+ const_set("BASH_VERSION", bash_version.freeze)
123
145
  end
124
146
  opts.on("--root PATH", "Project root directory") do |d|
125
147
  raise Errno::ENOENT, d unless File.directory? d
148
+
126
149
  options.root_directory = d
127
150
  end
128
151
  opts.on("--command-name NAME", "Value to use as SimpleCov.command_name") do |c|
@@ -143,5 +166,5 @@ module Bashcov
143
166
  end
144
167
 
145
168
  # Current Bash version (e.g. 4.2)
146
- BASH_VERSION = `#{bash_path} -c 'echo -n ${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}'`.freeze
169
+ BASH_VERSION = bash_version.freeze
147
170
  end
data/test.sh ADDED
@@ -0,0 +1,10 @@
1
+ #!/bin/bash
2
+
3
+ set -euo pipefail
4
+
5
+ jobs=$(grep -o '^[a-z].*:$' .gitlab-ci.yml | tr -d ':' | grep -Ev '^(before_script)$')
6
+
7
+ for job in $jobs; do
8
+ echo "Running ${job}..."
9
+ gitlab-runner exec docker "$job"
10
+ done
metadata CHANGED
@@ -1,45 +1,45 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bashcov
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.2
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cédric Félizard
8
- autorequire:
9
- bindir: bin
8
+ autorequire:
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2018-03-27 00:00:00.000000000 Z
11
+ date: 2023-04-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: simplecov
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '='
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.15.1
19
+ version: 0.21.2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '='
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.15.1
26
+ version: 0.21.2
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: aruba
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.14.3
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 0.14.3
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: coveralls
42
+ name: bundler-audit
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: mutant-rspec
70
+ name: rake
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: rake
84
+ name: rspec
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -95,7 +95,7 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: rspec
98
+ name: rubocop
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
@@ -109,7 +109,21 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: rubocop
112
+ name: rubocop-rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop-rspec
113
127
  requirement: !ruby/object:Gem::Requirement
114
128
  requirements:
115
129
  - - ">="
@@ -139,11 +153,17 @@ dependencies:
139
153
  description: Code coverage tool for Bash
140
154
  email:
141
155
  - cedric@felizard.fr
142
- executables:
143
- - bashcov
156
+ executables: []
144
157
  extensions: []
145
158
  extra_rdoc_files: []
146
159
  files:
160
+ - ".build.yml"
161
+ - ".github/FUNDING.yml"
162
+ - ".gitignore"
163
+ - ".gitlab-ci.yml"
164
+ - ".rspec"
165
+ - ".rubocop.yml"
166
+ - ".simplecov"
147
167
  - CHANGELOG.md
148
168
  - CONTRIBUTING.md
149
169
  - Gemfile
@@ -151,10 +171,11 @@ files:
151
171
  - LICENSE.txt
152
172
  - README.md
153
173
  - Rakefile
174
+ - TESTING.md
175
+ - USAGE.md
154
176
  - bashcov.gemspec
155
177
  - bin/bashcov
156
178
  - lib/bashcov.rb
157
- - lib/bashcov/bash_info.rb
158
179
  - lib/bashcov/detective.rb
159
180
  - lib/bashcov/errors.rb
160
181
  - lib/bashcov/field_stream.rb
@@ -163,11 +184,16 @@ files:
163
184
  - lib/bashcov/runner.rb
164
185
  - lib/bashcov/version.rb
165
186
  - lib/bashcov/xtrace.rb
187
+ - test.sh
166
188
  homepage: https://github.com/infertux/bashcov
167
189
  licenses:
168
190
  - MIT
169
- metadata: {}
170
- post_install_message:
191
+ metadata:
192
+ homepage_uri: https://github.com/infertux/bashcov
193
+ source_code_uri: https://github.com/infertux/bashcov
194
+ changelog_uri: https://github.com/infertux/bashcov/blob/master/CHANGELOG.md
195
+ rubygems_mfa_required: 'true'
196
+ post_install_message:
171
197
  rdoc_options: []
172
198
  require_paths:
173
199
  - lib
@@ -175,16 +201,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
175
201
  requirements:
176
202
  - - ">="
177
203
  - !ruby/object:Gem::Version
178
- version: 2.3.0
204
+ version: 3.0.0
179
205
  required_rubygems_version: !ruby/object:Gem::Requirement
180
206
  requirements:
181
207
  - - ">="
182
208
  - !ruby/object:Gem::Version
183
209
  version: '0'
184
210
  requirements: []
185
- rubyforge_project:
186
- rubygems_version: 2.7.4
187
- signing_key:
211
+ rubygems_version: 3.4.10
212
+ signing_key:
188
213
  specification_version: 4
189
- summary: Code coverage tool for Bash
214
+ summary: ''
190
215
  test_files: []
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Bashcov
4
- # Module exposing information concerning the installed Bash version
5
- # @note methods do not cache results because +bash_path+ can change at
6
- # runtime
7
- # @note receiver is expected to implement +bash_path+
8
- module BashInfo
9
- # @return [Boolean] Whether Bash supports +BASH_XTRACEFD+
10
- def bash_xtracefd?
11
- BASH_VERSION >= "4.1"
12
- end
13
-
14
- # @param [Integer] length the number of bytes to test; default 128
15
- # @return [Boolean] whether Bash supports a +PS4+ of at least a given
16
- # number of bytes
17
- # @see https://tiswww.case.edu/php/chet/bash/CHANGES
18
- # @note Item +i.+ under the +bash-4.2-release+ to +bash-4.3-alpha+ change
19
- # list notes that version 4.2 truncates +PS4+ if it is greater than 128
20
- # bytes.
21
- def truncated_ps4?(length = 128)
22
- ps4 = SecureRandom.base64(length)
23
- !`PS4=#{ps4} #{bash_path} 2>&1 1>&- -xc 'echo hello'`.start_with?(ps4)
24
- end
25
- end
26
- end