diff --git a/built_in/git_flow.rb b/built_in/git_flow.rb new file mode 100644 index 0000000..f2fb88c --- /dev/null +++ b/built_in/git_flow.rb @@ -0,0 +1,27 @@ +module Shift + module BuiltIn + class GitFlow + + class ValidationError < ShiftError + end + + def self.execute(arguments) + raise UnknownAction.new({message: "You should provide a valid action."}) unless !arguments[0].nil? + case arguments[0] + when :validate + GitFlow.validate + else + raise UnknownAction.new({message: "Unknown action: #{arguments[0]}."}) + end + end + + def self.validate + branches = BuiltIn::Sh.execute(["git branch -a"]) + raise ValidationError.new({message: "master branch is missing."}) if branches.match(/remotes\/origin\/master/).nil? + raise ValidationError.new({message: "develop branch is missing."}) if branches.match(/remotes\/origin\/develop/).nil? + non_git_flow_branches = branches.scan(/remotes\/origin\/(?!(feature|develop|master|release|hotfix))(.+)/) + raise ValidationError.new({message: "The following branches are not compatible with Git flow: #{non_git_flow_branches.join(', ')}"}) if non_git_flow_branches.count > 0 + end + end + end +end \ No newline at end of file diff --git a/built_in/github_community.rb b/built_in/github_community.rb new file mode 100644 index 0000000..7f2f999 --- /dev/null +++ b/built_in/github_community.rb @@ -0,0 +1,55 @@ +module Shift + module BuiltIn + class GithubCommunity + + class UnknownAction < ShiftError + end + + class ValidationError < ShiftErrors + end + + def self.execute(arguments) + raise UnknownAction.new({message: "You should provide a valid action."}) unless !arguments[0].nil? + case arguments[0] + when :validate + GithubCommunity.validate + else + raise UnknownAction.new({message: "Unknown action: #{arguments[0]}."}) + end + end + + def self.validate + errors = [] + errors.push({ severity: :error, message: "README.md is missing." }) if ! File.exists?("README.md") + GithubCommunity.validate_markdown("README.md", errors) if File.exists?("README.md") + errors.push({ severity: :error, message: "CONTRIBUTING.md is missing." }) if ! File.exists?("CONTRIBUTING.md") + GithubCommunity.validate_markdown("CONTRIBUTING.md", errors) if File.exists?("CONTRIBUTING.md") + errors.push({ severity: :warning, message: "MANIFESTO.md is missing." }) if ! File.exists?("MANIFESTO.md") + GithubCommunity.validate_markdown("MANIFESTO.md", errors) if File.exists?("MANIFESTO.md") + errors.push({ severity: :warning, message: "LICENSE is missing." }) if ! File.exists?("LICENSE") + errors.push({ severity: :warning, message: "CODE_OF_CONDUCT.md is missing." }) if ! File.exists?("CODE_OF_CONDUCT.md") + GithubCommunity.validate_markdown("CODE_OF_CONDUCT.md", errors) if File.exists?("CODE_OF_CONDUCT.md") + errors.push({ severity: :error, message: ".github is missing." }) if ! Dir.exist?(".github") + errors.push({ severity: :error, message: "ISSUE_TEMPLATE is missing." }) if ((! Dir.exist?(".github/ISSUE_TEMPLATE") || Dir.empty?(".github/ISSUE_TEMPLATE")) && + (! Dir.exist?(".github/issue_template") || Dir.empty?(".github/issue_template")) && + (! File.exists?(".github/ISSUE_TEMPLATE.md")) && + (! File.exists?(".github/issue_template.md"))) + errors.push({ severity: :error, message: "PULL_REQUEST_TEMPLATE is missing." }) if ((! Dir.exist?(".github/PULL_REQUEST_TEMPLATE") || Dir.empty?(".github/PULL_REQUEST_TEMPLATE")) && + (! Dir.exist?(".github/pull_request_template") || Dir.empty?(".github/pull_request_template")) && + (! File.exists?(".github/PULL_REQUEST_TEMPLATE.md")) && + (! File.exists?(".github/pull_request_template.md"))) + raise ValidationError.new(errors) if errors.count > 0 + end + + private + + def self.validate_markdown(file_path, errors) + begin + BuiltIn::Markdown.validate(file_path) + rescue MarkdownError => markdown_error + errors.push({ severity: :error, message: markdown_error.message }) + end + end + end + end +end \ No newline at end of file diff --git a/built_in/markdown.rb b/built_in/markdown.rb index f8223e6..3ca205f 100644 --- a/built_in/markdown.rb +++ b/built_in/markdown.rb @@ -3,10 +3,13 @@ module Shift - class MarkdownUnknownCommand < StandardError + class MarkdownError < StandardError end - class MarkdownContainsNotFoundLink < StandardError + class MarkdownUnknownCommand < MarkdownError + end + + class MarkdownContainsNotFoundLink < MarkdownError end module BuiltIn diff --git a/built_in/service.rb b/built_in/service.rb index 4d24ed3..ec10cb1 100644 --- a/built_in/service.rb +++ b/built_in/service.rb @@ -24,7 +24,7 @@ def execute(built_in_name, arguments) end def self.built_in_class_ref(built_in_name) - class_name = "BuiltIn::" + built_in_name.capitalize + class_name = "BuiltIn::" + built_in_name.shift_class begin return Shift.const_get(class_name) rescue NameError diff --git a/built_in/sh.rb b/built_in/sh.rb index c78c56b..e51c763 100644 --- a/built_in/sh.rb +++ b/built_in/sh.rb @@ -20,7 +20,7 @@ def self.execute(arguments) exit_status = thread.value.exitstatus end raise BuiltInFailed.new(result) if exit_status != 0 - return true + return result end end end diff --git a/shift.rb b/shift.rb index 66b4be4..809f190 100644 --- a/shift.rb +++ b/shift.rb @@ -1,8 +1,29 @@ module Shift class CommandFailed < StandardError end + + class ShiftError < StandardError + attr_accessor :error + + def initialize(error) + error[:severity] = :error if ! error.key?(:severity) + @error = error + super(error[:message]) + end + end + + class ShiftErrors < StandardError + attr_accessor :errors + + def initialize(errors = []) + errors.each { |error| error[:severity] = :error if ! error.key?(:severity) } + @errors = errors + super(errors.map { |error| error[:message] }.join('\n')) + end + end end +require_relative "string" require_relative "built_in/service" require_relative "filter/service" require_relative "rule/service" @@ -46,10 +67,20 @@ def respond_to_missing?(method_sym, private = false) def method_missing(method_sym, *arguments, &_block) return super if respond_to_missing?(method_sym) == false - return @filter_service.filter(method_sym.to_s, arguments) if @filter_service.can_be_executed?(method_sym.to_s) == true - return execute_rule(method_sym.to_s, arguments) if @rule_service.can_be_executed?(method_sym.to_s) == true - return @built_in_service.execute(method_sym.to_s, arguments) if @built_in_service.can_be_executed?(method_sym.to_s) == true - return super + begin + return @filter_service.filter(method_sym.to_s, arguments) if @filter_service.can_be_executed?(method_sym.to_s) == true + return execute_rule(method_sym.to_s, arguments) if @rule_service.can_be_executed?(method_sym.to_s) == true + return @built_in_service.execute(method_sym.to_s, arguments) if @built_in_service.can_be_executed?(method_sym.to_s) == true + return super + rescue Shift::ShiftError => shift_error + display_error(shift_error.error) + raise shift_error if shift_error.error[:severity] == :error + rescue Shift::ShiftErrors => shift_errors + shift_errors.errors.each { |error| display_error(error) } + raise shift_errors if shift_errors.errors.any? { |error| error[:severity] == :error } + rescue => e + raise e + end end private @@ -69,5 +100,14 @@ def execute_rule(method_sym, arguments) end return nil end + + def display_error(error) + case error[:severity] + when :error + puts "💥 Error: #{error[:message]}" + when :warning + puts "⚠️ Warning: #{error[:message]}" + end + end end end \ No newline at end of file diff --git a/spec/git_flow/git_flow_spec.rb b/spec/git_flow/git_flow_spec.rb new file mode 100644 index 0000000..4cf1cbb --- /dev/null +++ b/spec/git_flow/git_flow_spec.rb @@ -0,0 +1,34 @@ +require_relative "../../shift" + +mock_folder_name = "./spec/git_flow/mock" + +describe Shift::ShiftCore, "a user want to validate the presence of Git flow" do + context "with master branch missing" do + it "should not execute the :beta lane" do + core = Shift::ShiftCore.new + folder = Shift::ShiftFolder.new(mock_folder_name, 'missing_master') + expect { core.execute_lane(:beta, folder) }.to raise_error Shift::BuiltIn::GitFlow::ValidationError + end + end + context "with develop branch missing" do + it "should not execute the :beta lane" do + core = Shift::ShiftCore.new + folder = Shift::ShiftFolder.new(mock_folder_name, 'missing_develop') + expect { core.execute_lane(:beta, folder) }.to raise_error Shift::BuiltIn::GitFlow::ValidationError + end + end + context "with branch does not follow the Git flow standard" do + it "should not execute the :beta lane" do + core = Shift::ShiftCore.new + folder = Shift::ShiftFolder.new(mock_folder_name, 'not_follow_git_flow_standard') + expect { core.execute_lane(:beta, folder) }.to raise_error Shift::BuiltIn::GitFlow::ValidationError + end + end + context "with all the branches follow the Git flow standard" do + it "should execute the :beta lane" do + core = Shift::ShiftCore.new + folder = Shift::ShiftFolder.new(mock_folder_name, 'follow_git_flow_standard') + expect { core.execute_lane(:beta, folder) }.not_to raise_error + end + end +end \ No newline at end of file diff --git a/spec/git_flow/mock/follow_git_flow_standard b/spec/git_flow/mock/follow_git_flow_standard new file mode 100644 index 0000000..287cc13 --- /dev/null +++ b/spec/git_flow/mock/follow_git_flow_standard @@ -0,0 +1,10 @@ +before_all do + sh "rm -rf /tmp/follow_git_flow_standard" + sh "mkdir /tmp/follow_git_flow_standard; cd /tmp/follow_git_flow_standard; git init; touch empty; git add .; git commit -m 'Initial commit'; git checkout -b remotes/origin/master; git checkout -b remotes/origin/develop; git checkout -b remotes/origin/feature/toto; git checkout -b remotes/origin/release/0.4.1; git checkout -b remotes/origin/hotfix/fix-ci" +end + +lane :beta do + Dir.chdir("/tmp/follow_git_flow_standard") do + git_flow :validate + end +end \ No newline at end of file diff --git a/spec/git_flow/mock/missing_develop b/spec/git_flow/mock/missing_develop new file mode 100644 index 0000000..f8f09a3 --- /dev/null +++ b/spec/git_flow/mock/missing_develop @@ -0,0 +1,10 @@ +before_all do + sh "rm -rf /tmp/missing_develop" + sh "mkdir /tmp/missing_develop; cd /tmp/missing_develop; git init; touch empty; git add .; git commit -m 'Initial commit'; git checkout -b remotes/origin/master" +end + +lane :beta do + Dir.chdir("/tmp/missing_develop") do + git_flow :validate + end +end \ No newline at end of file diff --git a/spec/git_flow/mock/missing_master b/spec/git_flow/mock/missing_master new file mode 100644 index 0000000..9896498 --- /dev/null +++ b/spec/git_flow/mock/missing_master @@ -0,0 +1,10 @@ +before_all do + sh "rm -rf /tmp/missing_master" + sh "mkdir /tmp/missing_master; cd /tmp/missing_master; git init" +end + +lane :beta do + Dir.chdir("/tmp/missing_master") do + git_flow :validate + end +end \ No newline at end of file diff --git a/spec/git_flow/mock/not_follow_git_flow_standard b/spec/git_flow/mock/not_follow_git_flow_standard new file mode 100644 index 0000000..c2066d7 --- /dev/null +++ b/spec/git_flow/mock/not_follow_git_flow_standard @@ -0,0 +1,10 @@ +before_all do + sh "rm -rf /tmp/not_follow_git_flow_standard" + sh "mkdir /tmp/not_follow_git_flow_standard; cd /tmp/not_follow_git_flow_standard; git init; touch empty; git add .; git commit -m 'Initial commit'; git checkout -b remotes/origin/master; git checkout -b remotes/origin/develop; git checkout -b remotes/origin/feature/toto; git checkout -b remotes/origin/toto" +end + +lane :beta do + Dir.chdir("/tmp/not_follow_git_flow_standard") do + git_flow :validate + end +end \ No newline at end of file diff --git a/spec/github_community/github_community_spec.rb b/spec/github_community/github_community_spec.rb new file mode 100644 index 0000000..50c9394 --- /dev/null +++ b/spec/github_community/github_community_spec.rb @@ -0,0 +1,51 @@ +require_relative "../../shift" + +mock_folder_name = "./spec/github_community/mock" + +describe Shift::ShiftCore, "a user want to validate the implementation of Github community standard" do + context "with issue template files missing" do + it "should not execute the :beta lane" do + core = Shift::ShiftCore.new + Dir.chdir(mock_folder_name + '/missing_issue_template') do + folder = Shift::ShiftFolder.new('missing_issue_template') + expect { core.execute_lane(:beta, folder) }.to raise_error Shift::BuiltIn::GithubCommunity::ValidationError + end + end + end + context "with pull request template files missing" do + it "should not execute the :beta lane" do + core = Shift::ShiftCore.new + Dir.chdir(mock_folder_name + '/missing_pr_template') do + folder = Shift::ShiftFolder.new('missing_pr_template') + expect { core.execute_lane(:beta, folder) }.to raise_error Shift::BuiltIn::GithubCommunity::ValidationError + end + end + end + context "with readme file missing" do + it "should not execute the :beta lane" do + core = Shift::ShiftCore.new + Dir.chdir(mock_folder_name + '/missing_readme') do + folder = Shift::ShiftFolder.new('missing_readme') + expect { core.execute_lane(:beta, folder) }.to raise_error Shift::BuiltIn::GithubCommunity::ValidationError + end + end + end + context "with contibuting file missing" do + it "should not execute the :beta lane" do + core = Shift::ShiftCore.new + Dir.chdir(mock_folder_name + '/missing_contributing') do + folder = Shift::ShiftFolder.new('missing_contributing') + expect { core.execute_lane(:beta, folder) }.to raise_error Shift::BuiltIn::GithubCommunity::ValidationError + end + end + end + context "with all existing Github community files" do + it "should execute the :beta lane" do + core = Shift::ShiftCore.new + Dir.chdir(mock_folder_name + '/existing_github_community_files') do + folder = Shift::ShiftFolder.new('existing_github_community_files') + expect { core.execute_lane(:beta, folder) }.not_to raise_error + end + end + end +end \ No newline at end of file diff --git a/spec/github_community/mock/existing_github_community_files/.github/ISSUE_TEMPLATE.md b/spec/github_community/mock/existing_github_community_files/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/existing_github_community_files/.github/PULL_REQUEST_TEMPLATE.md b/spec/github_community/mock/existing_github_community_files/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/existing_github_community_files/CODE_OF_CONDUCT.md b/spec/github_community/mock/existing_github_community_files/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/existing_github_community_files/CONTRIBUTING.md b/spec/github_community/mock/existing_github_community_files/CONTRIBUTING.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/existing_github_community_files/LICENSE b/spec/github_community/mock/existing_github_community_files/LICENSE new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/existing_github_community_files/README.md b/spec/github_community/mock/existing_github_community_files/README.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/existing_github_community_files/Shiftfile b/spec/github_community/mock/existing_github_community_files/Shiftfile new file mode 100644 index 0000000..e1327ee --- /dev/null +++ b/spec/github_community/mock/existing_github_community_files/Shiftfile @@ -0,0 +1,3 @@ +lane :beta do + github_community :validate +end \ No newline at end of file diff --git a/spec/github_community/mock/missing_contributing/.github/ISSUE_TEMPLATE.md b/spec/github_community/mock/missing_contributing/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_contributing/.github/PULL_REQUEST_TEMPLATE.md b/spec/github_community/mock/missing_contributing/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_contributing/CODE_OF_CONDUCT.md b/spec/github_community/mock/missing_contributing/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_contributing/LICENSE b/spec/github_community/mock/missing_contributing/LICENSE new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_contributing/README.md b/spec/github_community/mock/missing_contributing/README.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_contributing/Shiftfile b/spec/github_community/mock/missing_contributing/Shiftfile new file mode 100644 index 0000000..e1327ee --- /dev/null +++ b/spec/github_community/mock/missing_contributing/Shiftfile @@ -0,0 +1,3 @@ +lane :beta do + github_community :validate +end \ No newline at end of file diff --git a/spec/github_community/mock/missing_issue_template/.github/PULL_REQUEST_TEMPLATE.md b/spec/github_community/mock/missing_issue_template/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_issue_template/CODE_OF_CONDUCT.md b/spec/github_community/mock/missing_issue_template/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_issue_template/CONTRIBUTING.md b/spec/github_community/mock/missing_issue_template/CONTRIBUTING.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_issue_template/LICENSE b/spec/github_community/mock/missing_issue_template/LICENSE new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_issue_template/README.md b/spec/github_community/mock/missing_issue_template/README.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_issue_template/Shiftfile b/spec/github_community/mock/missing_issue_template/Shiftfile new file mode 100644 index 0000000..e1327ee --- /dev/null +++ b/spec/github_community/mock/missing_issue_template/Shiftfile @@ -0,0 +1,3 @@ +lane :beta do + github_community :validate +end \ No newline at end of file diff --git a/spec/github_community/mock/missing_pr_template/.github/ISSUE_TEMPLATE.md b/spec/github_community/mock/missing_pr_template/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_pr_template/CODE_OF_CONDUCT.md b/spec/github_community/mock/missing_pr_template/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_pr_template/CONTRIBUTING.md b/spec/github_community/mock/missing_pr_template/CONTRIBUTING.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_pr_template/LICENSE b/spec/github_community/mock/missing_pr_template/LICENSE new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_pr_template/README.md b/spec/github_community/mock/missing_pr_template/README.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_pr_template/Shiftfile b/spec/github_community/mock/missing_pr_template/Shiftfile new file mode 100644 index 0000000..e1327ee --- /dev/null +++ b/spec/github_community/mock/missing_pr_template/Shiftfile @@ -0,0 +1,3 @@ +lane :beta do + github_community :validate +end \ No newline at end of file diff --git a/spec/github_community/mock/missing_readme/.github/ISSUE_TEMPLATE.md b/spec/github_community/mock/missing_readme/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_readme/.github/PULL_REQUEST_TEMPLATE.md b/spec/github_community/mock/missing_readme/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_readme/CODE_OF_CONDUCT.md b/spec/github_community/mock/missing_readme/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_readme/CONTRIBUTING.md b/spec/github_community/mock/missing_readme/CONTRIBUTING.md new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_readme/LICENSE b/spec/github_community/mock/missing_readme/LICENSE new file mode 100644 index 0000000..e69de29 diff --git a/spec/github_community/mock/missing_readme/Shiftfile b/spec/github_community/mock/missing_readme/Shiftfile new file mode 100644 index 0000000..e1327ee --- /dev/null +++ b/spec/github_community/mock/missing_readme/Shiftfile @@ -0,0 +1,3 @@ +lane :beta do + github_community :validate +end \ No newline at end of file diff --git a/string.rb b/string.rb new file mode 100644 index 0000000..71eb070 --- /dev/null +++ b/string.rb @@ -0,0 +1,5 @@ +class String + def shift_class + split('_').collect!(&:capitalize).join + end +end \ No newline at end of file