danger-samsao 0.1.0
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/.env.example +1 -0
- data/.gitignore +5 -0
- data/.rubocop.yml +28 -0
- data/.travis.yml +12 -0
- data/CHANGELOG.md +25 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +136 -0
- data/Guardfile +21 -0
- data/LICENSE.txt +22 -0
- data/README.md +230 -0
- data/Rakefile +22 -0
- data/bitrise.wrapper.yml +51 -0
- data/bitrise.yml +70 -0
- data/danger-samsao.gemspec +33 -0
- data/lib/danger_plugin.rb +1 -0
- data/lib/danger_samsao.rb +1 -0
- data/lib/samsao/actions.rb +53 -0
- data/lib/samsao/config.rb +21 -0
- data/lib/samsao/gem_version.rb +3 -0
- data/lib/samsao/helpers.rb +79 -0
- data/lib/samsao/plugin.rb +28 -0
- data/lib/samsao/regexp.rb +29 -0
- data/spec/matchers/have_error.rb +25 -0
- data/spec/matchers/have_no_error.rb +14 -0
- data/spec/matchers/have_no_warning.rb +14 -0
- data/spec/matchers/have_warning.rb +25 -0
- data/spec/samsao_branch_helper_spec.rb +66 -0
- data/spec/samsao_branching_model_spec.rb +41 -0
- data/spec/samsao_changelog_modified_spec.rb +48 -0
- data/spec/samsao_changelog_updated_spec.rb +87 -0
- data/spec/samsao_config_spec.rb +30 -0
- data/spec/samsao_feature_single_commit_spec.rb +42 -0
- data/spec/samsao_has_app_changes_spec.rb +102 -0
- data/spec/samsao_merge_commit_detected_spec.rb +81 -0
- data/spec/samsao_regexp_spec.rb +35 -0
- data/spec/samsao_spec.rb +9 -0
- data/spec/samsao_trivial_change_spec.rb +57 -0
- data/spec/samsao_work_in_progress_pr_spec.rb +50 -0
- data/spec/spec_helper.rb +56 -0
- metadata +240 -0
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# rubocop:disable Style/HashSyntax
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
require 'rubocop/rake_task'
|
6
|
+
|
7
|
+
task default: :check
|
8
|
+
|
9
|
+
task :check => [:lint, :tests]
|
10
|
+
|
11
|
+
task :lint => [:lint_ruby, :lint_danger]
|
12
|
+
|
13
|
+
desc 'Run RuboCop on the lib/specs directory'
|
14
|
+
RuboCop::RakeTask.new(:lint_ruby)
|
15
|
+
|
16
|
+
desc 'Ensure that the plugin passes `danger plugins lint`'
|
17
|
+
task :lint_danger do
|
18
|
+
sh 'bundle exec danger plugins lint --warnings-as-errors'
|
19
|
+
end
|
20
|
+
|
21
|
+
task :test => [:tests]
|
22
|
+
RSpec::Core::RakeTask.new(:tests)
|
data/bitrise.wrapper.yml
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
---
|
2
|
+
format_version: 1.4.0
|
3
|
+
default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
|
4
|
+
description: |-
|
5
|
+
This wrapper is configure in bitrise.io editor as the script to run. What it
|
6
|
+
does mainly is to simply clone the repository and forward the execution of the
|
7
|
+
workflow to the real build file (bitrise.yml) which is hosted in this repository.
|
8
|
+
|
9
|
+
To work, main workflow here must also be present in bitrise.yml, so main workflows
|
10
|
+
must be kept synchronized between the two.
|
11
|
+
|
12
|
+
Also, any change made to this file must be **manually** added to bitrise.io editor.
|
13
|
+
Simply copy/paste the content of this file into the web editor and press save.
|
14
|
+
|
15
|
+
To test locally using bitrise CLI, while at project root directory, simply do:
|
16
|
+
|
17
|
+
bitrise run <workflow> -c bitrise.wrapper.yml
|
18
|
+
|
19
|
+
See http://devcenter.bitrise.io/tips-and-tricks/use-bitrise-yml-from-repository/
|
20
|
+
for details on the technique.
|
21
|
+
|
22
|
+
trigger_map:
|
23
|
+
- push_branch: "develop"
|
24
|
+
workflow: "develop"
|
25
|
+
- pull_request_target_branch: "*"
|
26
|
+
pull_request_source_branch: "*"
|
27
|
+
workflow: "pr"
|
28
|
+
|
29
|
+
workflows:
|
30
|
+
_run_from_repo:
|
31
|
+
steps:
|
32
|
+
- activate-ssh-key@3.1.1:
|
33
|
+
title: Activate SSH credentials
|
34
|
+
run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}'
|
35
|
+
- git-clone@3.4.2:
|
36
|
+
title: Clone repository
|
37
|
+
- script@1.1.3:
|
38
|
+
title: Continue using repository bitrise.yml
|
39
|
+
inputs:
|
40
|
+
- content: |-
|
41
|
+
#!/bin/bash
|
42
|
+
set -ex
|
43
|
+
bitrise run "${BITRISE_TRIGGERED_WORKFLOW_ID}"
|
44
|
+
|
45
|
+
develop:
|
46
|
+
after_run:
|
47
|
+
- _run_from_repo
|
48
|
+
|
49
|
+
pr:
|
50
|
+
after_run:
|
51
|
+
- _run_from_repo
|
data/bitrise.yml
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
---
|
2
|
+
format_version: 1.4.0
|
3
|
+
default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
|
4
|
+
|
5
|
+
workflows:
|
6
|
+
# Main Workflows
|
7
|
+
|
8
|
+
develop:
|
9
|
+
before_run:
|
10
|
+
- _setup
|
11
|
+
|
12
|
+
after_run:
|
13
|
+
- _teardown
|
14
|
+
|
15
|
+
pr:
|
16
|
+
before_run:
|
17
|
+
- _setup
|
18
|
+
|
19
|
+
after_run:
|
20
|
+
- _teardown
|
21
|
+
|
22
|
+
# Composite Workflows
|
23
|
+
|
24
|
+
_setup:
|
25
|
+
before_run:
|
26
|
+
- _cache_pull
|
27
|
+
- _prepare
|
28
|
+
- _lint
|
29
|
+
- _test
|
30
|
+
|
31
|
+
_teardown:
|
32
|
+
after_run:
|
33
|
+
- _cache_push
|
34
|
+
|
35
|
+
# Private workflows
|
36
|
+
|
37
|
+
_cache_push:
|
38
|
+
steps:
|
39
|
+
- cache-push@0.9.4:
|
40
|
+
title: Push cache
|
41
|
+
run_if: .IsCI
|
42
|
+
inputs:
|
43
|
+
- cache_paths: |-
|
44
|
+
$HOME/.bundle
|
45
|
+
|
46
|
+
_cache_pull:
|
47
|
+
steps:
|
48
|
+
- cache-pull@0.9.2:
|
49
|
+
title: Pull cache
|
50
|
+
|
51
|
+
_lint:
|
52
|
+
steps:
|
53
|
+
- script@1.1.3:
|
54
|
+
title: Linting
|
55
|
+
inputs:
|
56
|
+
- content: bundle exec rake lint
|
57
|
+
|
58
|
+
_prepare:
|
59
|
+
steps:
|
60
|
+
- script@1.1.3:
|
61
|
+
title: Prepare (installing dependencies)
|
62
|
+
inputs:
|
63
|
+
- content: bundle install
|
64
|
+
|
65
|
+
_test:
|
66
|
+
steps:
|
67
|
+
- script@1.1.3:
|
68
|
+
title: Tests
|
69
|
+
inputs:
|
70
|
+
- content: bundle exec rake tests
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'samsao/gem_version.rb'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'danger-samsao'
|
9
|
+
spec.version = Samsao::VERSION
|
10
|
+
spec.authors = ['Samsao Development Inc.']
|
11
|
+
spec.email = ['mvachon@samsao.co']
|
12
|
+
spec.description = 'Danger plugin for Samsao PR guidelines.'
|
13
|
+
spec.summary = 'A longer description of danger-samsao.'
|
14
|
+
spec.homepage = 'https://github.com/samsao/danger-samsao'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ['lib']
|
21
|
+
|
22
|
+
spec.add_runtime_dependency 'danger-plugin-api', '~> 1.0'
|
23
|
+
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
25
|
+
spec.add_development_dependency 'guard', '~> 2.14'
|
26
|
+
spec.add_development_dependency 'guard-rubocop', '~> 1.2'
|
27
|
+
spec.add_development_dependency 'guard-rspec', '~> 4.7'
|
28
|
+
spec.add_development_dependency 'pry', '~> 0.11.0.pre2'
|
29
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
30
|
+
spec.add_development_dependency 'rubocop', '~> 0.41'
|
31
|
+
spec.add_development_dependency 'rspec', '~> 3.4'
|
32
|
+
spec.add_development_dependency 'yard', '~> 0.8'
|
33
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'samsao/plugin'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'samsao/gem_version'
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Samsao
|
2
|
+
# Actions mixin module
|
3
|
+
module Actions
|
4
|
+
# Fails when git branching model is not respected for PR branch name.
|
5
|
+
#
|
6
|
+
# @return [void]
|
7
|
+
def fail_when_wrong_branching_model
|
8
|
+
message = 'Your branch should be prefixed with feature/, fix/, trivial/ or release/!'
|
9
|
+
|
10
|
+
fail message unless respects_branching_model
|
11
|
+
end
|
12
|
+
|
13
|
+
# Fails when a feature branch have than one commit
|
14
|
+
#
|
15
|
+
# @return [void]
|
16
|
+
def fail_when_non_single_commit_feature
|
17
|
+
commit_count = git.commits.size
|
18
|
+
message = "Your feature branch should have a single commit but found #{commit_count}, squash them together!"
|
19
|
+
|
20
|
+
fail message if feature_branch? && commit_count > 1
|
21
|
+
end
|
22
|
+
|
23
|
+
# Fails when CHANGELOG is not updated on feature or fix branches
|
24
|
+
#
|
25
|
+
# @return [void]
|
26
|
+
def fail_when_changelog_update_missing
|
27
|
+
return if trivial_change?
|
28
|
+
|
29
|
+
message = 'You did a fix or a feature without updating CHANGELOG file!'
|
30
|
+
|
31
|
+
fail message unless changelog_modified?
|
32
|
+
end
|
33
|
+
|
34
|
+
# Fails when one or more merge commit is detected.
|
35
|
+
#
|
36
|
+
# @return [void]
|
37
|
+
def fail_when_merge_commit_detected
|
38
|
+
message = 'Some merge commits were detected, you must use rebase to sync with base branch.'
|
39
|
+
merge_commit_detector = /^Merge branch '#{github.branch_for_base}'/
|
40
|
+
|
41
|
+
fail message if git.commits.any? { |commit| commit.message =~ merge_commit_detector }
|
42
|
+
end
|
43
|
+
|
44
|
+
# Fails when CHANGELOG is not updated on feature or fix branches
|
45
|
+
#
|
46
|
+
# @return [void]
|
47
|
+
def warn_when_work_in_progess_pr
|
48
|
+
message = 'Do not merge, PR is a work in progess [WIP]!'
|
49
|
+
|
50
|
+
warn message if github.pr_title.include?('[WIP]')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Danger
|
2
|
+
# Samsao's config class
|
3
|
+
class SamsaoConfig
|
4
|
+
def initialize
|
5
|
+
@changelogs = ['CHANGELOG.md']
|
6
|
+
@sources = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def changelogs(*entries)
|
10
|
+
return @changelogs if entries.nil? || entries.empty?
|
11
|
+
|
12
|
+
@changelogs = entries
|
13
|
+
end
|
14
|
+
|
15
|
+
def sources(*entries)
|
16
|
+
return @sources if entries.nil? || entries.empty?
|
17
|
+
|
18
|
+
@sources = entries
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# rubocop:disable Style/PredicateName
|
2
|
+
|
3
|
+
module Samsao
|
4
|
+
# Helpers mixin module
|
5
|
+
module Helpers
|
6
|
+
# Check if any changelog were modified. When the helper receives nothing,
|
7
|
+
# changelogs defined by the config are used.
|
8
|
+
#
|
9
|
+
# @return [Boolean] True if any changelogs were modified in this commit
|
10
|
+
def changelog_modified?(*changelogs)
|
11
|
+
changelogs = config.changelogs if changelogs.nil? || changelogs.empty?
|
12
|
+
|
13
|
+
changelogs.any? { |changelog| git.modified_files.include?(changelog) }
|
14
|
+
end
|
15
|
+
|
16
|
+
# Return true if the current PR branch is a feature branch
|
17
|
+
#
|
18
|
+
# @return [void]
|
19
|
+
def feature_branch?
|
20
|
+
git_branch.start_with?('feature/')
|
21
|
+
end
|
22
|
+
|
23
|
+
# Return true if the current PR branch is a feature branch
|
24
|
+
#
|
25
|
+
# @return [void]
|
26
|
+
def fix_branch?
|
27
|
+
git_branch.start_with?('fix/')
|
28
|
+
end
|
29
|
+
|
30
|
+
# Return true if the current PR branch is a release branch
|
31
|
+
#
|
32
|
+
# @return [void]
|
33
|
+
def release_branch?
|
34
|
+
git_branch.start_with?('release/')
|
35
|
+
end
|
36
|
+
|
37
|
+
# Return true if the current PR branch is a trivial branch
|
38
|
+
#
|
39
|
+
# @return [void]
|
40
|
+
def trivial_branch?
|
41
|
+
git_branch.start_with?('trivial/')
|
42
|
+
end
|
43
|
+
|
44
|
+
# Return true if the current PR is a trivial change (branch is `trivial_branch?`)
|
45
|
+
# or PR title contains #trivial or #typo markers.
|
46
|
+
#
|
47
|
+
# @return [void]
|
48
|
+
def trivial_change?
|
49
|
+
trivial_branch? || ['#trivial', '#typo'].any? { |modifier| github.pr_title.include?(modifier) }
|
50
|
+
end
|
51
|
+
|
52
|
+
# Return true if any source files are in the git modified files list.
|
53
|
+
#
|
54
|
+
# @return [void]
|
55
|
+
def has_app_changes?(*sources)
|
56
|
+
sources = config.sources if sources.nil? || sources.empty?
|
57
|
+
|
58
|
+
sources.any? do |source|
|
59
|
+
pattern = Samsao::Regexp.from_matcher(source, when_string_pattern_prefix_with: '^')
|
60
|
+
|
61
|
+
modified_file?(pattern)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def git_branch
|
68
|
+
github.branch_for_head
|
69
|
+
end
|
70
|
+
|
71
|
+
def modified_file?(matcher)
|
72
|
+
!git.modified_files.grep(matcher).empty?
|
73
|
+
end
|
74
|
+
|
75
|
+
def respects_branching_model
|
76
|
+
feature_branch? || fix_branch? || release_branch? || trivial_branch?
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'samsao/actions'
|
2
|
+
require 'samsao/config'
|
3
|
+
require 'samsao/helpers'
|
4
|
+
require 'samsao/regexp'
|
5
|
+
|
6
|
+
module Danger
|
7
|
+
# Samsao's Danger plugin.
|
8
|
+
#
|
9
|
+
# @example See README.md
|
10
|
+
#
|
11
|
+
# @see samsao/danger-samsao
|
12
|
+
# @tags internal, private, enterprise
|
13
|
+
#
|
14
|
+
class DangerSamsao < Plugin
|
15
|
+
include Samsao::Actions
|
16
|
+
include Samsao::Helpers
|
17
|
+
|
18
|
+
# Enable to configure the plugin configuration object.
|
19
|
+
#
|
20
|
+
# @return [Array<String>] (if no block given)
|
21
|
+
def config(&block)
|
22
|
+
@config = Danger::SamsaoConfig.new if @config.nil?
|
23
|
+
return @config unless block_given?
|
24
|
+
|
25
|
+
@config.instance_eval(&block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Samsao
|
2
|
+
# Regexp utility methods
|
3
|
+
module Regexp
|
4
|
+
# Turns a source entry input into a Regexp. Uses rules from [from_matcher](#from_matcher)
|
5
|
+
# function and append a `^` to final regexp when the source if a pure String.
|
6
|
+
#
|
7
|
+
# @param matcher The source entry to transform into a Regexp
|
8
|
+
#
|
9
|
+
# @return [Regexp] The source entry as a regexp
|
10
|
+
def self.from_source(source)
|
11
|
+
from_matcher(source, when_string_pattern_prefix_with: '^')
|
12
|
+
end
|
13
|
+
|
14
|
+
# Turns an input into a Regexp. If the input is a String, it turns it
|
15
|
+
# into a Regexp and escape all special characters. If the input is already
|
16
|
+
# a Regexp, it returns it without modification.
|
17
|
+
#
|
18
|
+
# @param matcher The input matcher to transform into a Regexp
|
19
|
+
# @keyword when_string_pattern_prefix_with (Default: '') The prefix that should be added to
|
20
|
+
# final regexp when the input matcher is a string type
|
21
|
+
#
|
22
|
+
# @return [Regexp] The input as a regexp
|
23
|
+
def self.from_matcher(matcher, when_string_pattern_prefix_with: '')
|
24
|
+
return matcher if matcher.is_a?(::Regexp)
|
25
|
+
|
26
|
+
/#{when_string_pattern_prefix_with}#{::Regexp.quote(matcher)}/
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rspec/expectations'
|
2
|
+
|
3
|
+
RSpec::Matchers.define :have_error do |expected|
|
4
|
+
match do |actual|
|
5
|
+
actual.status_report[:errors].any? do |error|
|
6
|
+
expected.is_a?(Regexp) ? error =~ matcher : error.start_with?(expected)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
failure_message do |actual|
|
11
|
+
message = "expected that #{Danger} would have error '#{expected}'"
|
12
|
+
|
13
|
+
errors = actual.status_report[:errors]
|
14
|
+
if errors.empty?
|
15
|
+
message += ' but there is none'
|
16
|
+
return message
|
17
|
+
end
|
18
|
+
|
19
|
+
actual.status_report[:errors].each do |error|
|
20
|
+
message += "\n * #{error}"
|
21
|
+
end
|
22
|
+
|
23
|
+
message
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rspec/expectations'
|
2
|
+
|
3
|
+
RSpec::Matchers.define :have_no_error do
|
4
|
+
match do |actual|
|
5
|
+
actual.status_report[:errors].empty?
|
6
|
+
end
|
7
|
+
|
8
|
+
failure_message do |actual|
|
9
|
+
message = "expected that #{Danger} would have no error but found '#{actual.status_report[:errors].size}'"
|
10
|
+
actual.status_report[:errors].each do |error|
|
11
|
+
message += "\n * #{error}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|