Fourier improvements (#2676)

* Move Fourier to projects

* Add command to lint the Swift code

* Add command to lint fourier's code

* Add command to format Swift's code

* Update git hook to run fourier

* Add tests

* Fix the fourier path

* Add command to test Tuist
This commit is contained in:
Pedro Piñera Buendía 2021-03-17 16:19:06 +01:00 committed by GitHub
parent 9c1db8418d
commit cbc4e46275
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 317 additions and 219 deletions

View File

@ -34,7 +34,7 @@ jobs:
bundle install --jobs 4 --retry 3
- name: Unit tests
run: |
bundle exec rake test_fourier
./fourier test fourier
rubocop:
name: Rubocop
runs-on: ubuntu-latest

View File

@ -43,10 +43,10 @@ jobs:
bundle install --jobs 4 --retry 3
- name: Generate Xcode project
run: |
./bin/fourier generate tuist
./fourier generate tuist
- name: Build
run: |
./bin/fourier build tuist all
./fourier build tuist all
test:
name: Test with Xcode ${{ matrix.xcode }}
runs-on: macos-latest
@ -72,7 +72,7 @@ jobs:
bundle install --jobs 4 --retry 3
- name: Generate Xcode project
run: |
./bin/fourier generate tuist
./fourier generate tuist
- name: Test
run: |
./bin/fourier test tuist unit
./fourier test tuist unit

View File

@ -51,7 +51,7 @@ jobs:
bundle install --jobs 4 --retry 3
- name: Run tests
run: |
./bin/fourier test tuist unit
./fourier test tuist unit
release_build:
name: Release build with Xcode ${{ matrix.xcode }}
runs-on: macOS-latest
@ -127,4 +127,4 @@ jobs:
bundle config path vendor/bundle
bundle install --jobs 4 --retry 3
- name: Run tests
run: ./bin/fourier test tuist acceptance features/${{ matrix.feature }}.feature
run: ./fourier test tuist acceptance features/${{ matrix.feature }}.feature

View File

@ -1 +1 @@
(env/prepend-to-pathlist "PATH" (expand-path "./bin"))
(env/prepend-to-pathlist "PATH" (expand-path "."))

View File

@ -15,6 +15,8 @@ gem "rubyzip", "~> 2.3.0"
gem "ruby-macho", "~> 1.4"
gem "cli-ui", "~> 1.4"
gem "thor", "~> 1.1"
gem "octokit", "~> 4.20"
gem "zeitwerk", "~> 2.4"
group :test do
gem "mocha", "~> 1.12"
@ -31,7 +33,3 @@ end
group :development, :test do
gem "byebug", "~> 11.1"
end
gem "octokit", "~> 4.20"
gem "zeitwerk", "~> 2.4"

View File

@ -19,16 +19,6 @@ require "json"
require "zip"
require "macho"
desc("Runs the Fourier tests")
Rake::TestTask.new do |t|
t.name = "test_fourier"
t.libs += [File.expand_path("./tools/fourier/test", __dir__)]
test_root = File.expand_path("./tools/fourier/test", __dir__)
t.test_files = FileList[File.join(test_root, "**", "*_test.rb")]
t.verbose = false
t.warning = false
end
desc("Updates swift-doc binary with the latest version available.")
task :swift_doc_update do
root_dir = File.expand_path(__dir__)
@ -113,31 +103,6 @@ task :xcbeautify_update do
File.write(File.join(root_dir, "vendor/.xcbeautify.version"), XCBEAUTIFY_VERSION)
end
desc("Formats the code style")
task :style_correct do
system(code_style_path)
end
desc("Swift format check")
task :swift_format do
Kernel.system(swiftformat_path, "--lint", ".") || abort
end
desc("Swift lint check")
task :swift_lint do
Kernel.system(swiftlint_path) || abort
end
desc("Lints the Ruby code style")
task :style_ruby do
system("bundle", "exec", "rubocop")
end
desc("Corrects the issues with the Ruby style")
task :style_ruby_correct do
system("bundle", "exec", "rubocop", "-a")
end
desc("Builds and archive a release version of tuist and tuistenv for local testing.")
task :local_package do
package
@ -233,18 +198,6 @@ task :benchmark do
)
end
def swiftformat_path
File.expand_path("bin/swiftformat", __dir__)
end
def swiftlint_path
File.expand_path("bin/swiftlint", __dir__)
end
def code_style_path
File.expand_path("script/code_style.sh", __dir__)
end
def decrypt_secrets
Encrypted::Environment.load_from_ejson("secrets.ejson", private_key: ENV["SECRET_KEY"])
end

View File

@ -9,7 +9,7 @@ require "pathname"
require "bundler/setup"
# Load fourier's directory
fourier_directory = File.expand_path("../tools/fourier/lib", __dir__)
fourier_directory = File.expand_path("./projects/fourier/lib", __dir__)
$LOAD_PATH.unshift(fourier_directory) unless $LOAD_PATH.include?(fourier_directory)
# Load Fourier

View File

@ -1,3 +1,5 @@
#!/bin/bash
script/code_style.sh
./fourier lint tuist
./fourier lint fourier
./fourier format tuist

View File

@ -1,6 +1,15 @@
# frozen_string_literal: true
require "cli/ui"
require "zeitwerk"
require "thor"
loader = Zeitwerk::Loader.new
loader.push_dir(__dir__)
loader.inflector.inflect("github_client" => "GitHubClient")
loader.inflector.inflect("github" => "GitHub")
loader.setup
module Fourier
class CLI < Thor
desc "test", "Run tests"
@ -18,6 +27,12 @@ module Fourier
desc "edit", "Edit Tuist's project manifest in Xcode"
subcommand "edit", Commands::Edit
desc "lint", "Lint the project's code"
subcommand "lint", Commands::Lint
desc "format", "Format the project's code"
subcommand "format", Commands::Format
desc "focus TARGET", "Edit Tuist's project focusing on the target TARGET"
def focus(target)
Services::Focus.call(target: target)

View File

@ -2,8 +2,6 @@
module Fourier
module Commands
class Build < Base
autoload :Tuist, "fourier/commands/build/tuist"
desc "tuist SUBCOMMAND ...ARGS", "Build Tuist"
subcommand "tuist", Commands::Build::Tuist
end

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
module Fourier
module Commands
class Format < Base
desc "tuist", "Format the source code of the Tuist CLI"
option :fix, desc: "When passed, it fixes the issues", type: :boolean, default: false
def tuist
Services::Format::Tuist.call(fix: options[:fix])
end
end
end
end

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
module Fourier
module Commands
class Lint < Base
desc "tuist", "Lint the source code of the Tuist CLI"
option :fix, desc: "When passed, it fixes the issues", type: :boolean, default: false
def tuist
Services::Lint::Tuist.call(fix: options[:fix])
end
desc "fourier", "Lint the source code of the Fourier CLI"
option :fix, desc: "When passed, it fixes the issues", type: :boolean, default: false
def fourier
Services::Lint::Fourier.call(fix: options[:fix])
end
desc "all", "Lint all the code in the repository"
option :fix, desc: "When passed, it fixes the issues", type: :boolean, default: false
def all
Services::Lint::Tuist.call(fix: options[:fix])
Services::Lint::Fourier.call(fix: options[:fix])
end
end
end
end

View File

@ -2,10 +2,13 @@
module Fourier
module Commands
class Test < Base
autoload :Tuist, "fourier/commands/test/tuist"
desc "tuist SUBCOMMAND ...ARGS", "Run Tuist tests"
subcommand "tuist", Commands::Test::Tuist
desc "fourier", "Run Fourier tests"
def fourier
Services::Test::Fourier.call
end
end
end
end

View File

@ -2,6 +2,7 @@
module Fourier
module Constants
ROOT_DIRECTORY = File.expand_path("../../../..", __dir__)
VENDOR_DIRECTORY = File.expand_path("../../vendor", __dir__)
REPOSITORY = "tuist/tuist"
end
end

View File

@ -0,0 +1,30 @@
# frozen_string_literal: true
module Fourier
module Services
class Base
def self.call(*args, &block)
new(*args).call(&block)
end
def call
raise NotImplementedError
end
def root_directory
Fourier::Constants::ROOT_DIRECTORY
end
def fourier_directory
File.join(Fourier::Constants::ROOT_DIRECTORY, "projects/fourier")
end
def tuist_directory
File.join(Fourier::Constants::ROOT_DIRECTORY)
end
def vendor_path(path)
File.join(Fourier::Constants::VENDOR_DIRECTORY, path)
end
end
end
end

View File

@ -5,7 +5,7 @@ module Fourier
module Tuist
class All < Base
def call
Dir.chdir(Constants::ROOT_DIRECTORY) do
Dir.chdir(tuist_directory) do
Utilities::System.tuist("build")
end
end

View File

@ -5,7 +5,7 @@ module Fourier
module Tuist
class Support < Base
def call
Dir.chdir(Constants::ROOT_DIRECTORY) do
Dir.chdir(tuist_directory) do
Utilities::System.tuist("build", "TuistSupport")
end
end

View File

@ -4,7 +4,7 @@ module Fourier
module Edit
class Tuist < Base
def call
Dir.chdir(Constants::ROOT_DIRECTORY) do
Dir.chdir(tuist_directory) do
Utilities::System.tuist("edit", "--only-current-directory")
end
end

View File

@ -9,7 +9,7 @@ module Fourier
end
def call
Dir.chdir(Constants::ROOT_DIRECTORY) do
Dir.chdir(tuist_directory) do
Utilities::System.tuist("focus", target)
end
end

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
module Fourier
module Services
module Format
class Tuist < Base
attr_reader :fix
def initialize(fix:)
@fix = fix
end
def call
Dir.chdir(tuist_directory) do
arguments = [vendor_path("swiftformat"), ".", "--quiet"]
unless fix
arguments << "--lint"
end
Fourier::Utilities::System.system(*arguments)
end
end
end
end
end
end

View File

@ -10,7 +10,7 @@ module Fourier
end
def call
Dir.chdir(Constants::ROOT_DIRECTORY) do
Dir.chdir(tuist_directory) do
arguments = ["generate"]
arguments << "--open" if open
Utilities::System.tuist(*arguments)

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
module Fourier
module Services
module Lint
class Fourier < Base
attr_reader :fix
def initialize(fix:)
@fix = fix
end
def call
Dir.chdir(fourier_directory) do
gem_path = Gem.loaded_specs["rubocop"].full_gem_path
executable_path = File.join(gem_path, "exe/rubocop")
arguments = [executable_path]
arguments << "-A" if fix
Utilities::System.system(*arguments)
end
end
end
end
end
end

View File

@ -0,0 +1,22 @@
# frozen_string_literal: true
module Fourier
module Services
module Lint
class Tuist < Base
attr_reader :fix
def initialize(fix:)
@fix = fix
end
def call
Dir.chdir(tuist_directory) do
arguments = [vendor_path("swiftlint"), "--quiet"]
arguments << "autocorrect" if fix
Utilities::System.system(*arguments)
end
end
end
end
end
end

View File

@ -0,0 +1,26 @@
# frozen_string_literal: true
require "rake/testtask"
module Fourier
module Services
module Test
class Fourier < Base
def call
Dir.chdir(root_directory) do
lib_directory = File.expand_path("lib", fourier_directory)
test_directory = File.expand_path("test", fourier_directory)
test_paths = Dir.glob(File.join(fourier_directory, "test/**/*_test.rb"))
arguments = [
"ruby",
"-I#{lib_directory}",
"-I#{test_directory}",
"-e \"ARGV.each {|f| require f}\"",
*test_paths,
].join(" ")
Utilities::System.system(arguments)
end
end
end
end
end
end

View File

@ -18,7 +18,7 @@ module Fourier
args = ["--format", "pretty"]
args << if feature.nil?
File.join(Constants::ROOT_DIRECTORY, "features/")
File.join(tuist_directory, "features/")
else
feature
end

View File

@ -5,7 +5,7 @@ module Fourier
module Tuist
class Support < Base
def call
Dir.chdir(Constants::ROOT_DIRECTORY) do
Dir.chdir(tuist_directory) do
Utilities::System.tuist("test", "TuistSupport")
end
end

View File

@ -5,7 +5,7 @@ module Fourier
module Tuist
class Unit < Base
def call
Dir.chdir(Constants::ROOT_DIRECTORY) do
Dir.chdir(tuist_directory) do
Utilities::System.tuist("test")
end
end

View File

@ -0,0 +1,32 @@
# frozen_string_literal: true
require "test_helper"
module Fourier
module Services
module Format
class TuistTest < TestCase
def test_calls_system_with_the_right_arguments
# Given
subject = Services::Format::Tuist.new(fix: false)
Utilities::System
.expects(:system)
.with(subject.vendor_path("swiftformat"), ".", "--quiet", "--lint")
# When/Then
subject.call
end
def test_calls_system_with_the_right_arguments_when_fix_is_true
# Given
subject = Services::Format::Tuist.new(fix: true)
Utilities::System
.expects(:system)
.with(subject.vendor_path("swiftformat"), ".", "--quiet")
# When/Then
subject.call
end
end
end
end
end

View File

@ -0,0 +1,36 @@
# frozen_string_literal: true
require "test_helper"
module Fourier
module Services
module Lint
class FourierTest < TestCase
def test_calls_system_with_the_right_arguments
# Given
subject = Services::Lint::Fourier.new(fix: false)
gem_path = Gem.loaded_specs["rubocop"].full_gem_path
executable_path = File.join(gem_path, "exe/rubocop")
Utilities::System
.expects(:system)
.with(executable_path)
# When/Then
subject.call
end
def test_calls_system_with_the_right_arguments_when_fix_is_true
# Given
subject = Services::Lint::Fourier.new(fix: true)
gem_path = Gem.loaded_specs["rubocop"].full_gem_path
executable_path = File.join(gem_path, "exe/rubocop")
Utilities::System
.expects(:system)
.with(executable_path, "-A")
# When/Then
subject.call
end
end
end
end
end

View File

@ -0,0 +1,32 @@
# frozen_string_literal: true
require "test_helper"
module Fourier
module Services
module Lint
class TuistTest < TestCase
def test_calls_system_with_the_right_arguments
# Given
subject = Services::Lint::Tuist.new(fix: false)
Utilities::System
.expects(:system)
.with(subject.vendor_path("swiftlint"), "--quiet")
# When/Then
subject.call
end
def test_calls_system_with_the_right_arguments_when_fix_is_true
# Given
subject = Services::Lint::Tuist.new(fix: true)
Utilities::System
.expects(:system)
.with(subject.vendor_path("swiftlint"), "--quiet", "autocorrect")
# When/Then
subject.call
end
end
end
end
end

View File

@ -20,25 +20,27 @@ module Fourier
def test_call_when_no_feature_is_provided
# Given
@subject = Acceptance.new(feature: nil)
::Cucumber::Cli::Main
.expects(:execute)
.with(["--format", "pretty", File.join(Constants::ROOT_DIRECTORY, "features/")])
.with(["--format", "pretty", File.join(@subject.tuist_directory, "features/")])
# Then
Acceptance.call(feature: nil)
@subject.call
end
def test_raises_when_cucumber_returns_unsuncessfully
# Given
cucumber_error = StandardError.new("cucumber error")
@subject = Acceptance.new(feature: nil)
::Cucumber::Cli::Main
.expects(:execute)
.with(["--format", "pretty", File.join(Constants::ROOT_DIRECTORY, "features/")])
.with(["--format", "pretty", File.join(@subject.tuist_directory, "features/")])
.returns(cucumber_error)
# When
error = assert_raises(Acceptance::Error) do
Acceptance.call(feature: nil)
@subject.call
end
# Then

View File

@ -28,7 +28,7 @@ module Fourier
environment = {}
# Then
assert_raises(Utilities::GitHubClient::TokenNotFound) do
assert_raises(Fourier::Utilities::GitHubClient::TokenNotFound) do
Utilities::GitHubClient.new(environment: environment)
end
end

View File

@ -20,6 +20,7 @@ reporter_options = { color: true }
Minitest::Reporters.use!([Minitest::Reporters::DefaultReporter.new(reporter_options)])
require "mocha/minitest"
require "fourier"
class TestCase < MiniTest::Test

View File

@ -1,19 +0,0 @@
#!/bin/bash
echo "Running SwiftFormat..."
bin/swiftformat . --quiet
if [ $? -ne 0 ]
then
echo "Swiftformat detected issues, please add changes and commit again"
exit 1
else
echo "Running Swiftlint...";
bin/swiftlint lint --quiet
if [ $? -ne 0 ]
then
bin/swiftlint autocorrect --quiet
echo "Swiftlint detected issues, please add changes and commit again"
else
echo "Code is formatted and linted correctly. Proceeding with commit..."
exit 0
fi
fi

View File

@ -1,11 +0,0 @@
# frozen_string_literal: true
require "cli/ui"
module Fourier
autoload :CLI, "fourier/cli"
autoload :Commands, "fourier/commands"
autoload :Utilities, "fourier/utilities"
autoload :Services, "fourier/services"
autoload :Constants, "fourier/constants"
end

View File

@ -1,11 +0,0 @@
# frozen_string_literal: true
module Fourier
module Commands
autoload :Base, "fourier/commands/base"
autoload :Test, "fourier/commands/test"
autoload :Build, "fourier/commands/build"
autoload :Generate, "fourier/commands/generate"
autoload :GitHub, "fourier/commands/github"
autoload :Edit, "fourier/commands/edit"
end
end

View File

@ -1,12 +0,0 @@
# frozen_string_literal: true
module Fourier
module Services
autoload :Base, "fourier/services/base"
autoload :Build, "fourier/services/build"
autoload :Test, "fourier/services/test"
autoload :GitHub, "fourier/services/github"
autoload :Generate, "fourier/services/generate"
autoload :Edit, "fourier/services/edit"
autoload :Focus, "fourier/services/focus"
end
end

View File

@ -1,14 +0,0 @@
# frozen_string_literal: true
module Fourier
module Services
class Base
def self.call(*args, &block)
new(*args).call(&block)
end
def call
raise NotImplementedError
end
end
end
end

View File

@ -1,8 +0,0 @@
# frozen_string_literal: true
module Fourier
module Services
module Build
autoload :Tuist, "fourier/services/build/tuist"
end
end
end

View File

@ -1,11 +0,0 @@
# frozen_string_literal: true
module Fourier
module Services
module Build
module Tuist
autoload :All, "fourier/services/build/tuist/all"
autoload :Support, "fourier/services/build/tuist/support"
end
end
end
end

View File

@ -1,8 +0,0 @@
# frozen_string_literal: true
module Fourier
module Services
module Edit
autoload :Tuist, "fourier/services/edit/tuist"
end
end
end

View File

@ -1,8 +0,0 @@
# frozen_string_literal: true
module Fourier
module Services
module Generate
autoload :Tuist, "fourier/services/generate/tuist"
end
end
end

View File

@ -1,8 +0,0 @@
# frozen_string_literal: true
module Fourier
module Services
module GitHub
autoload :CancelWorkflows, "fourier/services/github/cancel_workflows"
end
end
end

View File

@ -1,8 +0,0 @@
# frozen_string_literal: true
module Fourier
module Services
module Test
autoload :Tuist, "fourier/services/test/tuist"
end
end
end

View File

@ -1,12 +0,0 @@
# frozen_string_literal: true
module Fourier
module Services
module Test
module Tuist
autoload :Unit, "fourier/services/test/tuist/unit"
autoload :Support, "fourier/services/test/tuist/support"
autoload :Acceptance, "fourier/services/test/tuist/acceptance"
end
end
end
end

View File

@ -1,8 +0,0 @@
# frozen_string_literal: true
module Fourier
module Utilities
autoload :GitHubClient, "fourier/utilities/github_client"
autoload :Secrets, "fourier/utilities/secrets"
autoload :System, "fourier/utilities/system"
end
end

View File

@ -16,7 +16,7 @@ By implementing our CLI tool within the repository we can better ensure the inte
Before running Fourier, make sure that you have the Ruby version specified in the `.ruby-version` file, and that you have fetched the [Bundler](https://bundler.io) dependencies specified in the `Gemfile` by running `bundle install`. Then, you can run the following command:
```
./bin/fourier --help
./fourier --help
```
It'll output the list of available commands that you can run.

View File

@ -11,11 +11,11 @@ Tuist employs a diverse suite tests that help ensure it works as intended and pr
Acceptance tests run the built `tuist` command line against a wide range of [fixtures](https://github.com/tuist/tuist/tree/main/fixtures) and verify its output and results. They are the slowest to run however provide the most coverage. The idea is to **test a few complete scenarios for each major feature**.
Those are written in [Cucumber](https://cucumber.io/docs) and Ruby and can be found in [features](https://github.com/tuist/tuist/tree/main/features). Those are run when calling `./bin/fourier test tuist acceptance`:
Those are written in [Cucumber](https://cucumber.io/docs) and Ruby and can be found in [features](https://github.com/tuist/tuist/tree/main/features). Those are run when calling `./fourier test tuist acceptance`:
```bash
# 3 is the line where the definition of the test starts
./bin/fourier test tuist acceptance features/generate-1.feature:3
./fourier test tuist acceptance features/generate-1.feature:3
```
<Message