Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@cdevinesr
Copy link
Contributor

@cdevinesr cdevinesr commented Jul 2, 2018

Revised the Dockerfile to use the official Bash images for improved
version-specific test coverage. These images are based on Alpine. Given that
we're only trying to support 3.2.57 and up (because OSX), coverage has been
set to only go that far back (though there are older versions available in
Docker image form if we would like to use them).

Revised the Dockerfile to use the official Bash images for improved
version-specific test coverage.  These images are based on Alpine.  Given that
we're only trying to support 3.2.57 and up (because OSX), coverage has been
set to only go that far back (though there are older versions available in
Docker image form if we would like to use them).
@cdevinesr cdevinesr requested a review from a team as a code owner July 2, 2018 17:32
Copy link
Member

@sublimino sublimino left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea @cdevinesr, thanks! Minor change requested, and I'll give it a test.

Dockerfile Outdated
@@ -1,8 +1,9 @@
FROM alpine:3.6
ARG bashver
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we set a default version of latest here please?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. This is actually my first time using ARG and the documentation I had read didn't make any mention of being able to set default values (though that seems like a no-brainer in retrospect). Thanks!

If not specified at build time, it should default to using
'bash:latest'.
Copy link
Contributor

@mbland mbland left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a minor comment. Very nice!

.travis.yml Outdated
docker run -it bats:latest --tap /opt/bats/test
for bashver in 3.2 4.0 4.1 4.2 4.3 4.4
do
docker build --build-arg bashver=${bashver} --tag bats:bash${bashver} .
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think per #114, the image should be bats/bats:bash${bashver}, correct?

Also, I'm partial to adding a dash, i.e. bats/bats:bash-${bashver}, but I'm not super concerned about it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was playing off the previously set versioning in the Travis CI config. That change is definitely doable.

The added dash is probably a bit more readable, too.

bats/bashX.Y -> bats/bats:bash-X.Y
@mbland
Copy link
Contributor

mbland commented Jul 2, 2018

Another couple quick questions:

  • Perhaps add a command to emit the Bash version before running the tests?
  • So if one of these fails, Travis'll recognize and still fail the build, right?

I see that all the builds currently pass on Travis, so that's comforting! :-)

@cdevinesr
Copy link
Contributor Author

cdevinesr commented Jul 2, 2018

I was operating under the assumption that Travis is essentially running under a set -e sort of mentality. I'll test on a localized branch with an intentionally failing test and see what it does.

Regarding emission of Bash version, I could have it add that to the Docker image. Would something like this be acceptable?

Sending build context to Docker daemon  852.5kB
Step 1/6 : ARG bashver=latest
Step 2/6 : FROM bash:${bashver}
latest: Pulling from library/bash
605ce1bd3f31: Pull complete
18ecc0d9c7d6: Pull complete
ff65c95dde64: Pull complete
Digest: sha256:f72240387ad0a579251a00c1d12dd12845e0d3336a3b518b5c267cdddf18f2f2
Status: Downloaded newer image for bash:latest
 ---> e6f9405e3ba1
Step 3/6 : RUN bash --version
 ---> Running in affacecf2837
GNU bash, version 4.4.23(1)-release (x86_64-pc-linux-musl)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Removing intermediate container affacecf2837
 ---> 51d9198615bb
Step 4/6 : RUN ln -s /opt/bats/bin/bats /usr/sbin/bats
 ---> Running in 3ed497669e20
Removing intermediate container 3ed497669e20
 ---> aa01de42869a
Step 5/6 : COPY . /opt/bats/
 ---> ec5ae3a6265f
Step 6/6 : ENTRYPOINT ["bash", "/usr/sbin/bats"]
 ---> Running in a78113edb0c8
Removing intermediate container a78113edb0c8
 ---> 451e944e85c6
Successfully built 451e944e85c6

My previous commits were relying on the building of the image showing the version via the loop variable, but I realize that's not as accurate as doing something like this.

@cdevinesr
Copy link
Contributor Author

Sure enough, it does not behave like set -e in the loop. Adjusting that now.

cdevinesr added 3 commits July 2, 2018 16:05
This is better _and more accurate) than relying on digging for the tag.
Travis doesn't operate under any sort of 'set -e' like principles.  The return
code provided matches the return code from the last thing to run.  This
change ensures the last thing to run is a check against any failures inside
the version loop.
Dockerfile Outdated
&& ln -s /opt/bats/bin/bats /usr/sbin/bats
FROM bash:${bashver}

RUN bash --version
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than baking this into the image, I'm wondering if you can update the .travis.yml script to run:

docker run -it bash:${bashver} --version

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming it does so after building the bats image for that version, that should work fine, yeah.

.travis.yml Outdated
docker build --build-arg bashver=${bashver} --tag bats/bats:bash-${bashver} .
docker run -it bats/bats:bash-${bashver} --tap /opt/bats/test || RC=1
done
[ ${RC} -eq 0 ]
Copy link
Contributor

@mbland mbland Jul 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking it might be nice to capture which version failed, something like this:

failures=()
for bashver in ...
do
  ...
  if ! docker run -t bats/bats:bash-${bashver} --tap /opt/bats/test; then
    failures="$(docker run bash:${bashver} -c 'echo $BASH_VERSION')"
  fi
done
if [[ "${#failures[@]}" -ne 0 ]]; then
  printf 'Bats failed under the following Bash versions:\n'
  printf -- '- %s\n' "${failures[@]}"
  false
fi

Thoughts? Make sense?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heh, realized I screwed up the first version of the code above, just edited it. Sorry for the spam.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you're going for and I like it. I can only assume Travis uses Bash for underlying shell stuff since [[ works. I'll mess with that and see if I can get it implemented.

@jasonkarns
Copy link
Member

jasonkarns commented Jul 2, 2018

Travis has the concept of a build matrix, which supports generating various cross configurations of OS/runtimes/environments.

We can generate the build matrix to test multiple versions of bash without using a for-loop. This will give us first-class reporting on the travis dashboard (a distinct build job for each bash version) as well as implicit "-e like" exiting.

image

PR (to this PR) here: cdevinesr#1

@jasonkarns
Copy link
Member

Related... correct me if I'm wrong, but for linux builds, the first step in the test script is redundant, no?

script:
- bash -c 'time bin/bats --tap test'
- |
   if [[ "$TRAVIS_OS_NAME" == 'linux' ]]; then
     "docker build"
   fi

We could change the test script to be:

script:
- |
   if [[ "$TRAVIS_OS_NAME" == 'linux' ]]; then
     "docker build"
   else
     bash -c 'time bin/bats --tap test'
   fi

Unless I'm missing something?

@cdevinesr
Copy link
Contributor Author

The only thing that initial test gets us over the added version coverage is timing, but that timing step could be added to the versioned checks instead, so we can get a better idea about performance on each Bash version. Unless there's a specific reason we'd need the tests executed directly under Linux but not inside Docker (I can't think of anything unique or special that would give us over just putting it into the version checks).

I'll merge your changes (still new to Travis and your implementation is much cleaner than what I was doing).

Bash version via build matrix instead of script loop
@jasonkarns
Copy link
Member

still new to Travis

no worries, the yml file can be ... obtuse.

For instance, the matrix.include is rather odd. If we left the os having both linux and osx, we'd end up with a 2x6 build matrix (12 jobs). Of course, all we want is the 1x6 linux builds (one for each bash version) and then an extra macOS build. The explicit matrix.include lets us add specific jobs after the build matrix has been calculated. (You can also do matrix.exclude in order to exclude build configurations that match a certain criteria, as well.)

@cdevinesr
Copy link
Contributor Author

Yeah, that's what I got from reading over your changes and the Travis documentation.

The more I think about it, the more I think perhaps the timing piece may not give us much extra. Travis already shows run time when running jobs, and there's not much I can think of offhand in terms of real benefits that we'd get from doing it manually with time instead. Thoughts?

Since this is now being tracked via Travis CI, we don't need (or want, likely)
to include the version check in the image build.
@mbland
Copy link
Contributor

mbland commented Jul 2, 2018

Hmm, can we set ENTRYPOINT ["bash", "-c", "time", "bats"] in the Dockerfile? It's not essential, but it's really handy to have the timing information from the build.

Alternatively, perhaps we should add time to Bats itself. Thoughts?

@cdevinesr
Copy link
Contributor Author

It doesn't work, since time bats [args] would need to all be one argument, which removes the ability to pass arguments on demand from the command line (which is the use case we're liable to see from end users).

It can be done with CMD, but again, we'd be forcing the image to only be a self-test image rather than an actual utility people can work with.

@cdevinesr
Copy link
Contributor Author

Alternatively, we could include two Dockerfiles - one that builds the image people would work with, and one that builds a 'testing' image that just performs the self test with CMD. We could simply reference the self-test Dockerfile during the build with -f.

@mbland
Copy link
Contributor

mbland commented Jul 2, 2018

Ah, asynchronous comments...

So the Travis build time factors in the time it takes for the environment to get set up, which can fluctuate. Running time shows the timing for just the test suite, after the environment's stable (including fetching Docker images).

Hmm, thought what I read in man bash suggested ["bash", "-c", "time", "bin/bats"] would work, but local experimentation demonstrates otherwise. Oh well.

That said, time docker run -it bats/bats:bash-${BASHVER} --tap /opt/bats/test might be fast enough for our purposes. Want to try it?

@cdevinesr
Copy link
Contributor Author

Looks pretty close to the timing we'd get wrapping the call to Bats itself:

ok 62 a failing test in a suite results in an error exit code
ok 63 running an ad-hoc suite by specifying multiple test files
ok 64 extended syntax in suite
ok 65 recursive support (short option)
ok 66 recursive support (long option)
real	0m2.462s
user	0m0.016s
sys	0m0.004s
The command "if [[ "$TRAVIS_OS_NAME" == 'linux' ]]; then
  docker build --build-arg bashver=${BASHVER} --tag bats/bats:bash-${BASHVER} .
  time docker run -it bats/bats:bash-${BASHVER} --tap /opt/bats/test
fi
" exited with 0.
Done. Your build exited with 0.

I'm good with it, personally.

This de-dupes the Bash 4.3 test by having all Linux-based testing happen
inside Docker.  Timing changes due to wrapping 'docker run' should be
negligible.
@mbland
Copy link
Contributor

mbland commented Jul 2, 2018

I'm going approve, but will let @sublimino register his approval as well.

For the record, though, I did crack the ENTRYPOINT nut with the help of https://unix.stackexchange.com/a/144519:

ENTRYPOINT ["bash", "-c", "time bats \"$@\"", "bats"]

And then after building:

$ time docker run -it bats/bats:latest --tap /opt/bats/test
1..66                                                            
ok 1 no arguments prints usage instructions
...
ok 66 recursive support (long option)      
                       
real    0m2.114s                     
user    0m0.630s                   
sys     0m0.060s                           
                                                           
real    0m3.313s                                            
user    0m0.070s                               
sys     0m0.036s

The first time output is from the ENTRYPOINT, and the second is from the time docker run invocation. So the time docker run time does include a bit of overhead, but I don't really like baking the command into the ENTRYPOINT, either.

Hence, time docker run is good enough for now.

@mbland
Copy link
Contributor

mbland commented Jul 2, 2018

BTW, I know this PR kinda ballooned into a more complex discussion pretty quickly, but thanks for your patience and persistence! It's going to be great having this level of coverage across Bash versions with every PR—props to @jasonkarns for the Travis magic, much better than my cruddy trickery.

Also, I certainly feel greatly edified by this whole exchange! Learned a few useful new things. I'd trigger the merge myself right now, but will let @sublimino do the honors if he's satisfied.

@sublimino
Copy link
Member

Awesome, I turn around for one evening and this happens! 😍

LGTM

Now all that's left is to push passing and built image versions to the docker hub. Does anybody have the keys to add secrets to Travis?

@sublimino
Copy link
Member

Btw @mbland @jasonkarns my instinct is to squash and merge this, which last time lost gpg signing. Do we have a preference on commit history maintenance? Asking users to rebase can be nightmarish for some etc etc

@jasonkarns
Copy link
Member

Meh. For most team repos, I'm strongly against squash merging (since you lose history); but that's primarily so we don't have orphaned branches that can't be tracked down. And that assumes some level of rebasing on the author's part.

Generally, I'm in favor of regular old merge commits.

@mbland
Copy link
Contributor

mbland commented Jul 3, 2018

@sublimino I'm OK not squashing, and I'm less prone to rebase than I used to be. I would say let's just hit the big "Merge pull request" button, but now that I'm really thinking about it, it would be nice to have a signed commit somewhere in the process.

First, could you hit the "Approve changes" link in the PR thread here first, just to clean that up? Then, do you want to push a local signed merge to master? Or I could do it. (And I wonder if we should do that as a course of habit.)

BTW, I'm thinking we could stand to put docker run -it bash:${bashver} --version back in to print the exact version of Bash in the container, but that's easy enough to add to a future PR. I'd rather just get this in ASAP than hold out for another tweak.

@cdevinesr At some point, could you check out https://help.github.com/articles/signing-commits-with-gpg/ so any future PRs will have GPG-signed/verified commits?

@cdevinesr
Copy link
Contributor Author

I've already planned to do so, and tried once before, but since I do most of my stuff from work, and I primarily use a variation of Cygwin (drive space limitations on my laptop that I have no way or authority to work around, unfortunately), gnupg does not seem to function properly on there.

I'm working on getting enough space available to put together small dev VM with Vagrant that I can get a GPG key set up on. I'll see about accomplishing that today.

@mbland
Copy link
Contributor

mbland commented Jul 3, 2018

@cdevinesr Well, don't let not having GPG set up be a blocker. If we end up doing signed merge commits as a matter of policy, it solves the immediate issue. Having incoming PRs with signed commits is more of a nice-to-have.

Oh, and since you're up and about, feel free to sneak that docker run -it bash:${bashver} --version back in there... 🙂 Only if you've a reasonable chance; I don't want to block this PR any further.

Also thinking we might want to specify BASHVER for the corresponding BASH_VERSIONs from stock Travis images, such as 4.3.11. Again, sneak that in if you can, but it shouldn't be a blocker.

@jasonkarns
Copy link
Member

I think as long as we sign the tagged release, that's sufficient; especially since that technically signs the tree up to that point. (And github signs merge commits, which is close.)

@mbland
Copy link
Contributor

mbland commented Jul 3, 2018

Oh crap, I hadn't noticed GitHub signs the merges. Makes sense they'd do that.

@sublimino Can you approve the review and just click the "Merge pull request" button, then?

@cdevinesr
Copy link
Contributor Author

The official Bash Docker images don't go to that level of granularity, unfortunately. They're broken down strictly by major and minor, and don't let you drill down by point release. The list of available Docker image tags can be found here.

I can add the version check back to the Docker image. I was avoiding it because it obviously adds another layer for something that merely outputs to the command line (so basically we'd have an "empty" layer), but if it's not a problem for you, I don't mind re-adding it. I think having that level of detail could prove useful in the long run, even with the dashboard covering major and minor for us.

This will let us collect information about which point release is
in use in the image.  Results in a lot less digging through
changelogs in the event of weirdness.
@mbland
Copy link
Contributor

mbland commented Jul 3, 2018

No, not as a layer in the Dockerfile, but as a command in the .travis.yml script!

docker build --build-arg bashver=${BASHVER} --tag bats/bats:bash-${BASHVER} .
docker run -it bash:${bashver} --version
time docker run -it bats/bats:bash-${BASHVER} --tap /opt/bats/test

Hmm, https://hub.docker.com/r/library/bash/tags/ does have tags that drill down to the patch level, but it seems only for the latest versions. Bummer.

@cdevinesr
Copy link
Contributor Author

Yeah, you're seeing what I was referring to. It makes sense to have a tag with point releases, but they don't keep one for each (that'd quickly turn into a lot of images to keep around).

And I see I did that Dockerfile update before your comment. I've reverted that and pushed your suggestion. Still waking up this morning.

@sublimino
Copy link
Member

Thanks again @cdevinesr and everybody - I'm ready to Push The Button in 2m

I'd be inclined to sign merges in the future as it reduces the amount of code to review and sign at "tagging time", but either effectively achieves the same end.

@sublimino sublimino merged commit 4b3c9e8 into bats-core:master Jul 3, 2018
@cdevinesr cdevinesr deleted the bash-version-coverage branch July 3, 2018 13:34
mbland added a commit that referenced this pull request Jul 3, 2018
Since I'm paranoid that we might need to resolve an issue specific to
4.3.11(1)-release (or whatever the Bash version is in the stock Travis
Linux image). Also, I didn't want to hold up #116 any longer with more
tiny requests.
rico-chet added a commit to rico-chet/bats-core that referenced this pull request Apr 10, 2020
Bats 1.1.0 - 2018-07-08

This is the first release with new features relative to the original Bats 0.4.0.

Added:
* The `-r, --recursive` flag to scan directory arguments recursively for
  `*.bats` files (bats-core#109)
* The `contrib/rpm/bats.spec` file to build RPMs (bats-core#111)

Changed:
* Travis exercises latest versions of Bash from 3.2 through 4.4 (bats-core#116, bats-core#117)
* Error output highlights invalid command line options (bats-core#45, bats-core#46, bats-core#118)
* Replaced `echo` with `printf` (bats-core#120)

Fixed:
* Fixed `BATS_ERROR_STATUS` getting lost when `bats_error_trap` fired multiple
  times under Bash 4.2.x (bats-core#110)
* Updated `bin/bats` symlink resolution, handling the case on CentOS where
  `/bin` is a symlink to `/usr/bin` (bats-core#113, bats-core#115)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants