learn-lab 0.1.0.rc1
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 +7 -0
- data/.circleci/config.yml +48 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.rubocop.yml +31 -0
- data/CHANGELOG.md +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +72 -0
- data/Rakefile +13 -0
- data/bin/ci +9 -0
- data/bin/console +14 -0
- data/bin/rspec +29 -0
- data/bin/rubocop +29 -0
- data/bin/setup +17 -0
- data/exe/learn-lab +6 -0
- data/learn-lab.gemspec +39 -0
- data/lib/learn_lab.rb +33 -0
- data/lib/learn_lab/cli.rb +57 -0
- data/lib/learn_lab/configuration.rb +42 -0
- data/lib/learn_lab/errors.rb +7 -0
- data/lib/learn_lab/file_system.rb +67 -0
- data/lib/learn_lab/prompt.rb +24 -0
- data/lib/learn_lab/test/parsers/mocha.rb +41 -0
- data/lib/learn_lab/test/parsers/null.rb +37 -0
- data/lib/learn_lab/test/parsers/rspec.rb +41 -0
- data/lib/learn_lab/test/runner.rb +45 -0
- data/lib/learn_lab/test/strategies/mocha.rb +54 -0
- data/lib/learn_lab/test/strategies/none.rb +22 -0
- data/lib/learn_lab/test/strategies/rspec.rb +44 -0
- data/lib/learn_lab/test/strategy.rb +74 -0
- data/lib/learn_lab/token.rb +30 -0
- data/lib/learn_lab/vcs.rb +24 -0
- data/lib/learn_lab/version.rb +5 -0
- metadata +180 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f02fc168601cfde48fab19367a3a9fcb2fa5a88f0c010e507b4c71329e06ecc2
|
4
|
+
data.tar.gz: d3e0e54341575734de538394c133a1b40952cf33dfb9481065a03d518e6e6650
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fda10060c1877e47e94b7d933b5adff5ea921e564732f93631d13d2c05cd06585034f4915df81573607734d9b043b5872da879baf126210386d17bbf8c101b7b
|
7
|
+
data.tar.gz: 0a8df382daa76d1b2ce64e134c30fec8d833620701783be28fdee2224448b98889a70387cf8605a755a2f6a9832e9fcc8944fdbde8ffe05775c08b1db3611e77
|
@@ -0,0 +1,48 @@
|
|
1
|
+
version: 2.1
|
2
|
+
jobs:
|
3
|
+
build:
|
4
|
+
parallelism: 1
|
5
|
+
docker:
|
6
|
+
- image: circleci/ruby:2.6.5-node-browsers
|
7
|
+
working_directory: ~/repo
|
8
|
+
steps:
|
9
|
+
- checkout
|
10
|
+
- restore_cache:
|
11
|
+
keys:
|
12
|
+
- v1-dependencies-{{ checksum "learn-lab.gemspec" }}
|
13
|
+
- v1-dependencies-
|
14
|
+
- run:
|
15
|
+
name: Install Dependencies
|
16
|
+
command: |
|
17
|
+
./bin/setup circleci
|
18
|
+
- save_cache:
|
19
|
+
paths:
|
20
|
+
- ./vendor/bundle
|
21
|
+
key: v1-dependencies-{{ checksum "learn-lab.gemspec" }}
|
22
|
+
- run:
|
23
|
+
name: Run CI Script
|
24
|
+
command: |
|
25
|
+
./bin/ci
|
26
|
+
- store_test_results:
|
27
|
+
path: /tmp/test-results
|
28
|
+
- store_artifacts:
|
29
|
+
path: /tmp/test-results
|
30
|
+
destination: test-results
|
31
|
+
workflows:
|
32
|
+
build:
|
33
|
+
jobs:
|
34
|
+
- build
|
35
|
+
nightly:
|
36
|
+
triggers:
|
37
|
+
- schedule:
|
38
|
+
cron: "0 0 * * *"
|
39
|
+
filters:
|
40
|
+
branches:
|
41
|
+
only:
|
42
|
+
- master
|
43
|
+
jobs:
|
44
|
+
- build
|
45
|
+
experimental:
|
46
|
+
notify:
|
47
|
+
branches:
|
48
|
+
only: master
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
AllCops:
|
2
|
+
NewCops: enable
|
3
|
+
Exclude:
|
4
|
+
- 'Gemfile'
|
5
|
+
- 'Rakefile'
|
6
|
+
- 'bin/*'
|
7
|
+
- 'spec/fixtures/**/*'
|
8
|
+
- 'tmp/**/*'
|
9
|
+
- 'vendor/bundle/**/*'
|
10
|
+
TargetRubyVersion: 2.5
|
11
|
+
|
12
|
+
Layout/SpaceAroundEqualsInParameterDefault:
|
13
|
+
EnforcedStyle: no_space
|
14
|
+
|
15
|
+
Metrics/BlockLength:
|
16
|
+
ExcludedMethods:
|
17
|
+
- describe
|
18
|
+
- context
|
19
|
+
- it
|
20
|
+
|
21
|
+
Layout/LineLength:
|
22
|
+
Max: 89
|
23
|
+
|
24
|
+
Style/BlockDelimiters:
|
25
|
+
EnforcedStyle: braces_for_chaining
|
26
|
+
|
27
|
+
Style/RaiseArgs:
|
28
|
+
EnforcedStyle: compact
|
29
|
+
|
30
|
+
Style/YodaCondition:
|
31
|
+
EnforcedStyle: require_for_equality_operators_only
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Changelog
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
|
+
|
7
|
+
## [Unreleased]
|
8
|
+
### Added
|
9
|
+
### Changed
|
10
|
+
### Removed
|
11
|
+
### Fixed
|
12
|
+
|
13
|
+
## [0.1.0.rc1]
|
14
|
+
Initial version with support for `config` and `test` commands.
|
15
|
+
|
16
|
+
[Unreleased]: https://github.com/flatiron-labs/learn-lab/compare/v0.1.0.rc1...HEAD
|
17
|
+
[0.1.0]: https://github.com/flatiron-labs/learn-lab/releases/tag/v0.1.0.rc1
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2020 Flatiron School
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# Learn Lab
|
2
|
+
|
3
|
+
The command line interface for Flatiron School enterprise.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
To install the gem, run:
|
8
|
+
|
9
|
+
```
|
10
|
+
$ gem install learn-lab
|
11
|
+
```
|
12
|
+
|
13
|
+
then run:
|
14
|
+
|
15
|
+
```
|
16
|
+
$ learn-lab config
|
17
|
+
```
|
18
|
+
|
19
|
+
to configure your settings.
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
From within a lesson directory, run:
|
24
|
+
|
25
|
+
```
|
26
|
+
$ learn-lab [command]
|
27
|
+
```
|
28
|
+
|
29
|
+
To see a list of available commands, run:
|
30
|
+
|
31
|
+
```
|
32
|
+
$ learn-lab help
|
33
|
+
```
|
34
|
+
|
35
|
+
## Development
|
36
|
+
|
37
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
38
|
+
|
39
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
40
|
+
|
41
|
+
This project uses RSpec for tests, and Rubocop for linting code. The default
|
42
|
+
Bundler generated scripts provided for both are in the `bin` folder. CI is
|
43
|
+
done through
|
44
|
+
[CircleCI](https://app.circleci.com/pipelines/github/flatiron-labs/learn-lab). All pushes to any branch will trigger a build that runs specs and lints the code.
|
45
|
+
|
46
|
+
### Cutting a New Release
|
47
|
+
|
48
|
+
Steps for releasing a new version:
|
49
|
+
|
50
|
+
* update the version number in `version.rb`
|
51
|
+
* update the CHANGELOG
|
52
|
+
- create a new release heading with the new version number and date
|
53
|
+
- create an empty [Unreleased] section with empty headings
|
54
|
+
- update links at the bottom to reflect new version
|
55
|
+
* commit the changes with a message like: "Prepping for release x.x.x"
|
56
|
+
* run `bundle exec rake release` -- this will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org)
|
57
|
+
* post a message in the `#engineering-all-staff` Slack channel announcing the new release
|
58
|
+
|
59
|
+
## Contributing
|
60
|
+
|
61
|
+
Bug reports and pull requests are welcome on
|
62
|
+
[GitHub](https://github.com/flatiron-labs/learn-lab/issues). To submit a pull request:
|
63
|
+
|
64
|
+
1. [Fork](https://github.com/flatiron-labs/learn-lab/fork) the repo
|
65
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
66
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
67
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
68
|
+
5. Create a new Pull Request
|
69
|
+
|
70
|
+
## License
|
71
|
+
|
72
|
+
Licensed under the [MIT License](https://github.com/flatiron-labs/learn-lab/blob/master/LICENSE.txt).
|
data/Rakefile
ADDED
data/bin/ci
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "learn_lab"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/rspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rspec' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rspec-core", "rspec")
|
data/bin/rubocop
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rubocop' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rubocop", "rubocop")
|
data/bin/setup
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
set -euo pipefail
|
3
|
+
IFS=$'\n\t'
|
4
|
+
|
5
|
+
if [ "${1-}" = "circleci" ]; then
|
6
|
+
echo "== Installing Bundler =="
|
7
|
+
gem install bundler:2.1.4
|
8
|
+
echo "== Running Bundle Install =="
|
9
|
+
bundle install --jobs=4 --retry=3 --path ./vendor/bundle && bundle clean
|
10
|
+
else
|
11
|
+
echo "== Running Bundle Install =="
|
12
|
+
bundle install
|
13
|
+
fi
|
14
|
+
|
15
|
+
echo "== Running NPM Install for Spec Fixtures =="
|
16
|
+
npm install --prefix spec/fixtures/mocha/mocha-app/
|
17
|
+
npm install --prefix spec/fixtures/mocha/mocha-with-failures/
|
data/exe/learn-lab
ADDED
data/learn-lab.gemspec
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/learn_lab/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'learn-lab'
|
7
|
+
spec.version = LearnLab::VERSION
|
8
|
+
spec.authors = ['Flatiron School']
|
9
|
+
spec.email = ['learn@flatironschool.com']
|
10
|
+
|
11
|
+
spec.summary = 'The command line interface for Flatiron School enterprise.'
|
12
|
+
spec.homepage = 'https://github.com/flatiron-labs/learn-lab'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
|
15
|
+
|
16
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org/'
|
17
|
+
spec.metadata['changelog_uri'] = 'https://github.com/flatiron-labs/learn-lab/blob/master/CHANGELOG.md'
|
18
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
19
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
20
|
+
|
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{^(test|spec|features)/}) }
|
25
|
+
end
|
26
|
+
|
27
|
+
spec.bindir = 'exe'
|
28
|
+
spec.executables = ['learn-lab']
|
29
|
+
spec.require_paths = ['lib']
|
30
|
+
|
31
|
+
spec.add_development_dependency 'aruba', '~> 1.0'
|
32
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
33
|
+
spec.add_development_dependency 'rspec', '~> 3.9'
|
34
|
+
spec.add_development_dependency 'rspec_junit_formatter', '~> 0.4'
|
35
|
+
spec.add_development_dependency 'rubocop', '~> 1.0'
|
36
|
+
|
37
|
+
spec.add_runtime_dependency 'git', '~> 1.7'
|
38
|
+
spec.add_runtime_dependency 'thor', '~> 1.0'
|
39
|
+
end
|
data/lib/learn_lab.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
require 'json'
|
5
|
+
require 'git'
|
6
|
+
require 'thor'
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
require 'learn_lab/configuration'
|
10
|
+
require 'learn_lab/errors'
|
11
|
+
require 'learn_lab/file_system'
|
12
|
+
require 'learn_lab/prompt'
|
13
|
+
require 'learn_lab/test/runner'
|
14
|
+
require 'learn_lab/test/parsers/mocha'
|
15
|
+
require 'learn_lab/test/parsers/null'
|
16
|
+
require 'learn_lab/test/parsers/rspec'
|
17
|
+
require 'learn_lab/test/strategy'
|
18
|
+
require 'learn_lab/test/strategies/mocha'
|
19
|
+
require 'learn_lab/test/strategies/none'
|
20
|
+
require 'learn_lab/test/strategies/rspec'
|
21
|
+
require 'learn_lab/token'
|
22
|
+
require 'learn_lab/vcs'
|
23
|
+
require 'learn_lab/version'
|
24
|
+
|
25
|
+
require 'learn_lab/cli'
|
26
|
+
|
27
|
+
# Top-level module
|
28
|
+
#
|
29
|
+
module LearnLab
|
30
|
+
def self.file_system
|
31
|
+
FileSystem.new
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LearnLab
|
4
|
+
# Command-line interface.
|
5
|
+
#
|
6
|
+
class CLI < Thor
|
7
|
+
desc 'test', 'Run tests and get a token'
|
8
|
+
long_desc <<-LONG_DESC
|
9
|
+
`learn-lab test` will run your tests and output a token that can be
|
10
|
+
copy/pasted into Canvas.
|
11
|
+
LONG_DESC
|
12
|
+
# rubocop:disable Metrics/AbcSize
|
13
|
+
# rubocop:disable Metrics/MethodLength
|
14
|
+
def test
|
15
|
+
configuration = Configuration.open
|
16
|
+
unless configuration.valid?
|
17
|
+
puts 'Please run `learn-lab config` first'
|
18
|
+
exit 0
|
19
|
+
end
|
20
|
+
repo = VCS.new(LearnLab.file_system.pwd)
|
21
|
+
results = LearnLab::Test::Runner.new(repo).run
|
22
|
+
exit 0 unless results[:failure_count].zero?
|
23
|
+
token = Token.new(configuration.email, repo.remote_url)
|
24
|
+
puts "Your token is:\n\n"
|
25
|
+
puts chunk(token.encoded, 30)
|
26
|
+
end
|
27
|
+
# rubocop:enable Metrics/AbcSize
|
28
|
+
# rubocop:enable Metrics/MethodLength
|
29
|
+
|
30
|
+
desc 'config', 'Configure gem'
|
31
|
+
long_desc <<-LONG_DESC
|
32
|
+
`learn-lab config` will configure this gem. It will prompt you for any
|
33
|
+
information it needs and save the configuration to a file in your $HOME directory.
|
34
|
+
LONG_DESC
|
35
|
+
def config
|
36
|
+
configuration = Configuration.open
|
37
|
+
email = configuration.email || '<not set>'
|
38
|
+
|
39
|
+
question = "Enter the email you use to log into Canvas\n" \
|
40
|
+
"(your current email is '#{email}'):"
|
41
|
+
|
42
|
+
prompt = Prompt.new
|
43
|
+
|
44
|
+
# TODO: What kind of email validation do we want here?
|
45
|
+
configuration.email = prompt.ask(question) { |value| !value.empty? }
|
46
|
+
|
47
|
+
configuration.save!
|
48
|
+
puts 'Configuration saved!'
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def chunk(string, size)
|
54
|
+
string.scan(/.{1,#{size}}/)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LearnLab
|
4
|
+
# Interface for dealing with persisted configuration file in YAML format.
|
5
|
+
#
|
6
|
+
class Configuration
|
7
|
+
attr_reader :path, :fs
|
8
|
+
attr_accessor :email
|
9
|
+
|
10
|
+
def self.open(filename='enterprise.yml', **options)
|
11
|
+
fs = options.fetch(:fs) { LearnLab.file_system }
|
12
|
+
path = fs.join(fs.home, '.flatiron-school', filename)
|
13
|
+
data = fs.read_yaml_file(path)
|
14
|
+
new(path, data)
|
15
|
+
rescue ConfigurationError
|
16
|
+
path = fs.join(fs.home, '.flatiron-school', 'enterprise.yml')
|
17
|
+
new(path, {})
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(path, data, **options)
|
21
|
+
@path = path
|
22
|
+
@fs = options.fetch(:fs) { LearnLab.file_system }
|
23
|
+
@email = data[:email]
|
24
|
+
end
|
25
|
+
|
26
|
+
def save!
|
27
|
+
directory = fs.dirname(path)
|
28
|
+
fs.mkdir(directory) unless fs.directory?(directory)
|
29
|
+
fs.write_yaml_file(path, payload, mode: 'w')
|
30
|
+
end
|
31
|
+
|
32
|
+
def valid?
|
33
|
+
!email.nil?
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def payload
|
39
|
+
{ 'email' => email }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LearnLab
|
4
|
+
# Wraps file system related commands.
|
5
|
+
#
|
6
|
+
class FileSystem
|
7
|
+
def read_file(path)
|
8
|
+
File.read(path)
|
9
|
+
end
|
10
|
+
|
11
|
+
def read_yaml_file(path, fallback: {})
|
12
|
+
data = YAML.load_file(path, fallback: fallback)
|
13
|
+
data.transform_keys(&:to_sym)
|
14
|
+
rescue Errno::ENOENT, Psych::SyntaxError => e
|
15
|
+
raise ConfigurationError.new(e)
|
16
|
+
end
|
17
|
+
|
18
|
+
def read_json_file(path)
|
19
|
+
data = File.exist?(path) ? read_file(path) : '{}'
|
20
|
+
JSON.parse(data, symbolize_names: true)
|
21
|
+
end
|
22
|
+
|
23
|
+
def home
|
24
|
+
Dir.home
|
25
|
+
end
|
26
|
+
|
27
|
+
def pwd
|
28
|
+
FileUtils.pwd
|
29
|
+
end
|
30
|
+
|
31
|
+
def join(*args)
|
32
|
+
File.join(*args)
|
33
|
+
end
|
34
|
+
|
35
|
+
def dirname(path)
|
36
|
+
File.dirname(path)
|
37
|
+
end
|
38
|
+
|
39
|
+
def mkdir(path)
|
40
|
+
FileUtils.mkdir_p(path)
|
41
|
+
end
|
42
|
+
|
43
|
+
def directory?(path)
|
44
|
+
File.directory?(path)
|
45
|
+
end
|
46
|
+
|
47
|
+
def write_yaml_file(path, data, **options)
|
48
|
+
File.write(path, data.to_yaml, **options)
|
49
|
+
end
|
50
|
+
|
51
|
+
def file_exist?(path)
|
52
|
+
File.exist?(path)
|
53
|
+
end
|
54
|
+
|
55
|
+
def dir_exist?(path)
|
56
|
+
Dir.exist?(path)
|
57
|
+
end
|
58
|
+
|
59
|
+
def dir_entries(path)
|
60
|
+
Dir.entries(path)
|
61
|
+
end
|
62
|
+
|
63
|
+
def rm(path)
|
64
|
+
FileUtils.rm(path)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LearnLab
|
4
|
+
# Special prompt that keeps asking for input until it is valid.
|
5
|
+
#
|
6
|
+
class Prompt
|
7
|
+
attr_reader :output
|
8
|
+
|
9
|
+
def initialize(output=$stdout)
|
10
|
+
@output = output
|
11
|
+
end
|
12
|
+
|
13
|
+
def ask(question, &block)
|
14
|
+
input_is_valid = false
|
15
|
+
until input_is_valid
|
16
|
+
output.print("\n#{question} > ")
|
17
|
+
answer = $stdin.gets.chomp
|
18
|
+
input_is_valid = block_given? ? block.call(answer) : true
|
19
|
+
end
|
20
|
+
|
21
|
+
answer
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LearnLab
|
4
|
+
module Test
|
5
|
+
module Parsers
|
6
|
+
# Parse Mocha test result output
|
7
|
+
#
|
8
|
+
class Mocha
|
9
|
+
attr_reader :output
|
10
|
+
|
11
|
+
def initialize(output)
|
12
|
+
@output = output
|
13
|
+
end
|
14
|
+
|
15
|
+
def framework
|
16
|
+
'mocha'
|
17
|
+
end
|
18
|
+
|
19
|
+
def duration
|
20
|
+
output ? output[:stats][:duration] : 0
|
21
|
+
end
|
22
|
+
|
23
|
+
def example_count
|
24
|
+
output ? output[:stats][:tests] : 1
|
25
|
+
end
|
26
|
+
|
27
|
+
def passing_count
|
28
|
+
output ? output[:stats][:passes] : 0
|
29
|
+
end
|
30
|
+
|
31
|
+
def pending_count
|
32
|
+
output ? output[:stats][:pending] : 0
|
33
|
+
end
|
34
|
+
|
35
|
+
def failure_count
|
36
|
+
output ? output[:stats][:failures] : 1
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LearnLab
|
4
|
+
module Test
|
5
|
+
module Parsers
|
6
|
+
# Null parser. Used when no test suite has been detected.
|
7
|
+
#
|
8
|
+
class Null
|
9
|
+
attr_reader :output
|
10
|
+
|
11
|
+
def framework
|
12
|
+
'none'
|
13
|
+
end
|
14
|
+
|
15
|
+
def duration
|
16
|
+
0
|
17
|
+
end
|
18
|
+
|
19
|
+
def example_count
|
20
|
+
0
|
21
|
+
end
|
22
|
+
|
23
|
+
def passing_count
|
24
|
+
0
|
25
|
+
end
|
26
|
+
|
27
|
+
def pending_count
|
28
|
+
0
|
29
|
+
end
|
30
|
+
|
31
|
+
def failure_count
|
32
|
+
0
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LearnLab
|
4
|
+
module Test
|
5
|
+
module Parsers
|
6
|
+
# Parse RSpec test result output.
|
7
|
+
#
|
8
|
+
class Rspec
|
9
|
+
attr_reader :output
|
10
|
+
|
11
|
+
def initialize(output)
|
12
|
+
@output = output
|
13
|
+
end
|
14
|
+
|
15
|
+
def framework
|
16
|
+
'rspec'
|
17
|
+
end
|
18
|
+
|
19
|
+
def duration
|
20
|
+
output ? output[:summary][:duration] : 0
|
21
|
+
end
|
22
|
+
|
23
|
+
def example_count
|
24
|
+
output ? output[:summary][:example_count] : 1
|
25
|
+
end
|
26
|
+
|
27
|
+
def passing_count
|
28
|
+
example_count - failure_count - pending_count
|
29
|
+
end
|
30
|
+
|
31
|
+
def pending_count
|
32
|
+
output ? output[:summary][:pending_count] : 0
|
33
|
+
end
|
34
|
+
|
35
|
+
def failure_count
|
36
|
+
output ? output[:summary][:failure_count] : 1
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LearnLab
|
4
|
+
module Test
|
5
|
+
# Runs a test suite. Lifted from the `learn-test` gem without Ironboard
|
6
|
+
# related code.
|
7
|
+
#
|
8
|
+
class Runner
|
9
|
+
attr_reader :repo, :options
|
10
|
+
|
11
|
+
def initialize(repo, options={})
|
12
|
+
@repo = repo
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
strategy.check_dependencies
|
18
|
+
strategy.run
|
19
|
+
results = strategy.results
|
20
|
+
strategy.cleanup unless options.fetch(:keep, false)
|
21
|
+
results
|
22
|
+
end
|
23
|
+
|
24
|
+
def working_directory
|
25
|
+
repo.working_directory
|
26
|
+
end
|
27
|
+
|
28
|
+
def strategy
|
29
|
+
@strategy ||= begin
|
30
|
+
detected = strategies.map { |s| s.new(self) }.detect(&:detect)
|
31
|
+
detected || LearnLab::Test::Strategies::None.new(self)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def strategies
|
38
|
+
[
|
39
|
+
LearnLab::Test::Strategies::Mocha,
|
40
|
+
LearnLab::Test::Strategies::Rspec
|
41
|
+
]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LearnLab
|
4
|
+
module Test
|
5
|
+
module Strategies
|
6
|
+
# Test strategy for Mocha.
|
7
|
+
#
|
8
|
+
class Mocha < Strategy
|
9
|
+
def check_dependencies
|
10
|
+
msg = 'Please install NodeJS: https://nodejs.org/en/download'
|
11
|
+
raise MissingDependencyError.new(msg) if `which node`.empty?
|
12
|
+
end
|
13
|
+
|
14
|
+
def detect
|
15
|
+
js_dependency?(:mocha) || js_dependency?(:'learn-browser')
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
command = if js_dependency?(:'learn-browser') || js_test_script?
|
20
|
+
'npm test'
|
21
|
+
else
|
22
|
+
'node_modules/.bin/mocha -R mocha-multi ' \
|
23
|
+
"--reporter-options spec=-,json=#{result_filename}"
|
24
|
+
end
|
25
|
+
system(command)
|
26
|
+
end
|
27
|
+
|
28
|
+
def parser
|
29
|
+
@parser ||= LearnLab::Test::Parsers::Mocha.new(output)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def js_package
|
35
|
+
@js_package ||= begin
|
36
|
+
path = fs.join(runner.working_directory, 'package.json')
|
37
|
+
fs.read_json_file(path)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def js_dependency?(dep)
|
42
|
+
%i[dependencies devDependencies].any? do |key|
|
43
|
+
js_package[key] && js_package[key][dep]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def js_test_script?
|
48
|
+
(js_package[:scripts] && js_package[:scripts][:test] || '') \
|
49
|
+
.include?(result_filename)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LearnLab
|
4
|
+
module Test
|
5
|
+
module Strategies
|
6
|
+
# Null strategy object used when no test suite is detected.
|
7
|
+
#
|
8
|
+
class None < Strategy
|
9
|
+
def run
|
10
|
+
out.puts <<~MSG
|
11
|
+
This directory doesn't appear to have any specs in it, so
|
12
|
+
there’s no test to run.
|
13
|
+
MSG
|
14
|
+
end
|
15
|
+
|
16
|
+
def parser
|
17
|
+
@parser ||= LearnLab::Test::Parsers::Null.new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LearnLab
|
4
|
+
module Test
|
5
|
+
module Strategies
|
6
|
+
# Test Strategy for RSpec. Mostly lifted from the `learn-test` gem
|
7
|
+
# without Ironboard specific code. Some other refactorings were also
|
8
|
+
# made to improve test coverage and fix Rubocop warnings.
|
9
|
+
#
|
10
|
+
class Rspec < Strategy
|
11
|
+
def detect
|
12
|
+
spec_dir = fs.join(runner.working_directory, 'spec')
|
13
|
+
fs.dir_exist?(spec_dir) && \
|
14
|
+
(fs.dir_entries(spec_dir).include?('spec_helper.rb') || \
|
15
|
+
fs.dir_entries(spec_dir).include?('rails_helper.rb'))
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
command_options = [
|
20
|
+
'--format documentation',
|
21
|
+
'--format j',
|
22
|
+
"--out #{result_filename}"
|
23
|
+
]
|
24
|
+
system("#{bundle_command}rspec #{command_options.join(' ')}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def parser
|
28
|
+
@parser ||= LearnLab::Test::Parsers::Rspec.new(output)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def bundle_command
|
34
|
+
bundler? ? 'bundle exec ' : ''
|
35
|
+
end
|
36
|
+
|
37
|
+
def bundler?
|
38
|
+
fs.file_exist?('Gemfile') && \
|
39
|
+
!!fs.read_file('Gemfile').match(/^\s*gem\s*('|")rspec(-[^'"]+)?('|").*$/)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LearnLab
|
4
|
+
module Test
|
5
|
+
# Base class for all test tools. Extracted from the `learn-test` gem with
|
6
|
+
# some modifications (i.e. this doesn't talk to Ironboard).
|
7
|
+
#
|
8
|
+
class Strategy
|
9
|
+
attr_reader :runner, :options, :out, :fs
|
10
|
+
|
11
|
+
def initialize(runner, out=$stdout)
|
12
|
+
@runner = runner
|
13
|
+
@options = runner.options
|
14
|
+
@out = out
|
15
|
+
@fs = LearnLab.file_system
|
16
|
+
end
|
17
|
+
|
18
|
+
def check_dependencies; end
|
19
|
+
|
20
|
+
def run
|
21
|
+
raise NotImplementedError.new(
|
22
|
+
'you must implement how this strategy runs its tests'
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def parser
|
27
|
+
raise NotImplementedError.new('you must define a parser')
|
28
|
+
end
|
29
|
+
|
30
|
+
# rubocop:disable Metrics/MethodLength
|
31
|
+
def results
|
32
|
+
{
|
33
|
+
repo_name: runner.repo,
|
34
|
+
build: {
|
35
|
+
test_suite: [{
|
36
|
+
framework: parser.framework,
|
37
|
+
formatted_output: output,
|
38
|
+
duration: parser.duration
|
39
|
+
}]
|
40
|
+
},
|
41
|
+
example_count: parser.example_count,
|
42
|
+
passing_count: parser.passing_count,
|
43
|
+
pending_count: parser.pending_count,
|
44
|
+
failure_count: parser.failure_count
|
45
|
+
}
|
46
|
+
end
|
47
|
+
# rubocop:enable Metrics/MethodLength
|
48
|
+
|
49
|
+
def output
|
50
|
+
return unless result_file?
|
51
|
+
|
52
|
+
fs.read_json_file(result_file_path)
|
53
|
+
end
|
54
|
+
|
55
|
+
def cleanup
|
56
|
+
fs.rm(result_file_path) if result_file?
|
57
|
+
end
|
58
|
+
|
59
|
+
def result_filename
|
60
|
+
'.results.json'
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def result_file?
|
66
|
+
fs.file_exist?(result_file_path)
|
67
|
+
end
|
68
|
+
|
69
|
+
def result_file_path
|
70
|
+
fs.join(runner.working_directory, result_filename)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LearnLab
|
4
|
+
# Encodable token. Consists of an email, GitHub URL, and timestamp encoded
|
5
|
+
# as a Base64 URL safe string.
|
6
|
+
#
|
7
|
+
class Token
|
8
|
+
attr_reader :email, :url, :timestamp
|
9
|
+
|
10
|
+
def initialize(email, url, timestamp=Time.now.utc)
|
11
|
+
@email = email
|
12
|
+
@url = url
|
13
|
+
@timestamp = timestamp
|
14
|
+
end
|
15
|
+
|
16
|
+
def encoded
|
17
|
+
Base64.urlsafe_encode64(payload.to_json)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def payload
|
23
|
+
{
|
24
|
+
lms_email: email,
|
25
|
+
vcs_url: url,
|
26
|
+
timestamp: timestamp
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LearnLab
|
4
|
+
# Adapter for the Version Control System.
|
5
|
+
#
|
6
|
+
class VCS
|
7
|
+
def initialize(directory, &block)
|
8
|
+
@repo = Git.open(directory)
|
9
|
+
rescue StandardError => e
|
10
|
+
msg = "You don't appear to be in a Learn lesson's directory. Please " \
|
11
|
+
'cd to an appropriate directory and try again.'
|
12
|
+
|
13
|
+
block_given? ? block.call(msg, e) : raise(LearnLab::Error.new(msg))
|
14
|
+
end
|
15
|
+
|
16
|
+
def remote_url
|
17
|
+
@repo.remote.url
|
18
|
+
end
|
19
|
+
|
20
|
+
def working_directory
|
21
|
+
@repo.dir.path
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: learn-lab
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0.rc1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Flatiron School
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-11-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: aruba
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '13.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '13.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.9'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.9'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec_junit_formatter
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.4'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.4'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: git
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.7'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.7'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: thor
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.0'
|
111
|
+
description:
|
112
|
+
email:
|
113
|
+
- learn@flatironschool.com
|
114
|
+
executables:
|
115
|
+
- learn-lab
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- ".circleci/config.yml"
|
120
|
+
- ".gitignore"
|
121
|
+
- ".rspec"
|
122
|
+
- ".rubocop.yml"
|
123
|
+
- CHANGELOG.md
|
124
|
+
- Gemfile
|
125
|
+
- LICENSE.txt
|
126
|
+
- README.md
|
127
|
+
- Rakefile
|
128
|
+
- bin/ci
|
129
|
+
- bin/console
|
130
|
+
- bin/rspec
|
131
|
+
- bin/rubocop
|
132
|
+
- bin/setup
|
133
|
+
- exe/learn-lab
|
134
|
+
- learn-lab.gemspec
|
135
|
+
- lib/learn_lab.rb
|
136
|
+
- lib/learn_lab/cli.rb
|
137
|
+
- lib/learn_lab/configuration.rb
|
138
|
+
- lib/learn_lab/errors.rb
|
139
|
+
- lib/learn_lab/file_system.rb
|
140
|
+
- lib/learn_lab/prompt.rb
|
141
|
+
- lib/learn_lab/test/parsers/mocha.rb
|
142
|
+
- lib/learn_lab/test/parsers/null.rb
|
143
|
+
- lib/learn_lab/test/parsers/rspec.rb
|
144
|
+
- lib/learn_lab/test/runner.rb
|
145
|
+
- lib/learn_lab/test/strategies/mocha.rb
|
146
|
+
- lib/learn_lab/test/strategies/none.rb
|
147
|
+
- lib/learn_lab/test/strategies/rspec.rb
|
148
|
+
- lib/learn_lab/test/strategy.rb
|
149
|
+
- lib/learn_lab/token.rb
|
150
|
+
- lib/learn_lab/vcs.rb
|
151
|
+
- lib/learn_lab/version.rb
|
152
|
+
homepage: https://github.com/flatiron-labs/learn-lab
|
153
|
+
licenses:
|
154
|
+
- MIT
|
155
|
+
metadata:
|
156
|
+
allowed_push_host: https://rubygems.org/
|
157
|
+
changelog_uri: https://github.com/flatiron-labs/learn-lab/blob/master/CHANGELOG.md
|
158
|
+
homepage_uri: https://github.com/flatiron-labs/learn-lab
|
159
|
+
source_code_uri: https://github.com/flatiron-labs/learn-lab
|
160
|
+
post_install_message:
|
161
|
+
rdoc_options: []
|
162
|
+
require_paths:
|
163
|
+
- lib
|
164
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
165
|
+
requirements:
|
166
|
+
- - ">="
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: 2.5.0
|
169
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 1.3.1
|
174
|
+
requirements: []
|
175
|
+
rubyforge_project:
|
176
|
+
rubygems_version: 2.7.6
|
177
|
+
signing_key:
|
178
|
+
specification_version: 4
|
179
|
+
summary: The command line interface for Flatiron School enterprise.
|
180
|
+
test_files: []
|