Skip to content

Commit

Permalink
Merge branch 'docker'
Browse files Browse the repository at this point in the history
  • Loading branch information
mislav committed Oct 29, 2019
2 parents fdcb2e1 + 95d49ba commit d492aba
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 94 deletions.
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*
!Gemfile
!Gemfile.lock
30 changes: 9 additions & 21 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ This project adheres to a [Code of Conduct][code-of-conduct]. By participating,

You will need:

1. Go 1.9+
1. Go 1.11+
1. Ruby 1.9+ with Bundler
2. git 1.8+
3. tmux & zsh (optional) - for running shell completion tests

If setting up either Go or Ruby for development proves to be a pain, you can
run the test suite in a prepared Docker container via `script/docker`.

## What makes a good hub feature

hub is a tool that wraps git to provide useful integration with GitHub. A new
Expand All @@ -28,7 +31,7 @@ feature is a good idea for hub if it improves some workflow for a GitHub user.

## How to install dependencies and run tests

1. [Clone the project](./README.md#source) into your GOPATH
1. [Clone the project](./README.md#source)
2. Verify that existing tests pass:
`make test-all`
3. Create a topic branch:
Expand All @@ -49,23 +52,8 @@ dependency.

## How to write tests

The new test suite is written in Cucumber under `features/` directory. Each
scenario is actually making real invocations to `hub` on the command-line in the
context of a real (dynamically created) git repository.

Whenever a scenario requires talking to the GitHub API, a fake HTTP server is
spun locally to replace the real GitHub API. This is done so that the test suite
runs faster and is available offline as well. The fake API server is defined
as a Sinatra app inline in each scenario:

```
Given the GitHub API server:
"""
post('/repos/github/hub/pulls') {
status 200
}
"""
```
Go unit tests are in `*_test.go` files and are runnable with `make test`. These
run really fast (under 10s).

The best way to learn to write new tests is to study the existing scenarios for
commands that are similar to those that you want to add or change.
However, most hub functionality is exercised through integration-style tests
written in Cucumber. See [Features](./features) for more info.
24 changes: 24 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM ruby:2.6

RUN apt-get update \
&& apt-get install -y sudo golang --no-install-recommends
RUN apt-get purge --auto-remove -y curl \
&& rm -rf /var/lib/apt/lists/*

RUN groupadd -r app && useradd -r -g app -G sudo app \
&& mkdir -p /home/app && chown -R app:app /home/app
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

USER app

# throw errors if Gemfile has been modified since Gemfile.lock
RUN bundle config --global frozen 1

WORKDIR /home/app/workdir

COPY Gemfile Gemfile.lock ./
RUN bundle install

ENV LANG C.UTF-8
ENV GOFLAGS -mod=vendor
ENV USER app
67 changes: 0 additions & 67 deletions Vagrantfile

This file was deleted.

49 changes: 49 additions & 0 deletions features/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Cucumber features for hub

How to run all features:

```sh
make bin/cucumber
bin/cucumber
```

Because this can take a couple of minutes, you may want to only run select files
related to the functionality that you're developing:

```sh
bin/cucumber feature/api.feature
```

The Cucumber test suite requires a Ruby development environment. If you want to
avoid setting that up, you can run tests inside a Docker container:

```sh
script/docker feature/api.feature
```

## How it works

Each scenario is actually making real invocations to `hub` on the command-line
in the context of a real (dynamically created) git repository.

Whenever a scenario requires talking to the GitHub API, a fake HTTP server is
spun locally to replace the real GitHub API. This is done so that the test suite
runs faster and is available offline as well. The fake API server is defined
as a Sinatra app inline in each scenario:

```
Given the GitHub API server:
"""
post('/repos/github/hub/pulls') {
status 200
}
"""
```

## How to write new tests

The best way to learn to write new tests is to study the existing scenarios for
commands that are similar to those that you want to add or change.

Since Cucumber tests are written in a natural language, you mostly don't need to
know Ruby to write new tests.
1 change: 1 addition & 0 deletions features/api.feature
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@cache_clear
Feature: hub api
Background:
Given I am "octokitten" on github.com with OAuth token "OTOKEN"
Expand Down
2 changes: 1 addition & 1 deletion features/steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
Dir.mktmpdir do |tmpdir|
Dir.chdir(tmpdir) do
`git init --quiet`
`git commit --quiet -m 'empty' --allow-empty`
`GIT_COMMITTER_NAME=a GIT_COMMITTER_EMAIL=b git commit --quiet -m 'empty' --allow-empty --author='a <b>'`
`git bundle create "#{dest}" master 2>&1`
end
end
Expand Down
22 changes: 17 additions & 5 deletions features/support/env.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@

system_git = `which git 2>/dev/null`.chomp
bin_dir = File.expand_path('../fakebin', __FILE__)

tmpdir = Dir.mktmpdir('hub_test')
tmp_bin_dir = "#{tmpdir}/bin"
Aruba.configure do |aruba|
aruba.send(:find_option, :root_directory).value = tmpdir
end

hub_dir = Dir.mktmpdir('hub_build')
raise 'hub build failed' unless system("./script/build -o #{hub_dir}/hub")

Expand All @@ -16,7 +23,7 @@
# speed up load time by skipping RubyGems
'RUBYOPT' => '--disable-gems',
# put fakebin on the PATH
'PATH' => "#{hub_dir}:#{bin_dir}:#{ENV['PATH']}",
'PATH' => "#{hub_dir}:#{tmp_bin_dir}:#{bin_dir}:#{ENV['PATH']}",
# clear out GIT if it happens to be set
'GIT' => nil,
# exclude this project's git directory from use in testing
Expand All @@ -25,7 +32,7 @@
'GIT_PROXY_COMMAND' => 'echo',
# avoids reading from current user's "~/.gitconfig"
'HOME' => expand_path('home'),
'TMPDIR' => expand_path('tmp'),
'TMPDIR' => tmpdir,
# https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables
'XDG_CONFIG_HOME' => nil,
'XDG_CONFIG_DIRS' => nil,
Expand All @@ -40,7 +47,7 @@
# reset current localization settings
'LANG' => nil,
'LANGUAGE' => nil,
'LC_ALL' => 'en_US.UTF-8',
'LC_ALL' => 'C.UTF-8',
# ignore current user's token
'GITHUB_TOKEN' => nil,
'GITHUB_USER' => nil,
Expand All @@ -62,7 +69,11 @@

After do
@server.stop if defined? @server and @server
FileUtils.rm_f("#{bin_dir}/vim")
FileUtils.rm_f("#{tmp_bin_dir}/vim")
end

After('@cache_clear') do
FileUtils.rm_rf("#{tmpdir}/hub/api")
end

RSpec::Matchers.define :be_successfully_executed do
Expand Down Expand Up @@ -114,7 +125,8 @@ def edit_hub_config
end

define_method(:text_editor_script) do |bash_code|
File.open("#{bin_dir}/vim", 'w', 0755) { |exe|
FileUtils.mkdir_p(tmp_bin_dir)
File.open("#{tmp_bin_dir}/vim", 'w', 0755) { |exe|
exe.puts "#!/bin/bash"
exe.puts "set -e"
exe.puts bash_code
Expand Down
20 changes: 20 additions & 0 deletions script/docker
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/bash
# Usage: script/docker [<cucumber-args>]
set -e

container=hub-test
workdir=/home/app/workdir

docker build -t "$container" .

docker run -it --rm -v "$PWD":"$workdir" -w "$workdir" "$container" \
/bin/bash -c "
# Enables running WEBrick server (see local_server.rb)
# https://stackoverflow.com/a/45899937/11687
cp /etc/hosts /tmp/hosts.new \
&& sed -i 's/::1\\tlocalhost/::1/' /tmp/hosts.new \
&& sudo cp -f /tmp/hosts.new /etc/hosts || exit 1
go test ./...
bundle exec cucumber $@
"

0 comments on commit d492aba

Please sign in to comment.