gitlab-triage 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +19 -0
  3. data/.gitignore +15 -0
  4. data/.gitlab-ci.yml +101 -0
  5. data/.gitlab/issue_templates/Policy.md +32 -0
  6. data/.rubocop.yml +6 -0
  7. data/Gemfile +4 -0
  8. data/Guardfile +70 -0
  9. data/README.md +13 -0
  10. data/Rakefile +6 -0
  11. data/bin/gitlab-triage +63 -0
  12. data/gitlab-triage.gemspec +29 -0
  13. data/lib/gitlab/triage.rb +6 -0
  14. data/lib/gitlab/triage/command_builders/base_command_builder.rb +32 -0
  15. data/lib/gitlab/triage/command_builders/cc_command_builder.rb +19 -0
  16. data/lib/gitlab/triage/command_builders/comment_command_builder.rb +23 -0
  17. data/lib/gitlab/triage/command_builders/label_command_builder.rb +19 -0
  18. data/lib/gitlab/triage/command_builders/status_command_builder.rb +23 -0
  19. data/lib/gitlab/triage/engine.rb +146 -0
  20. data/lib/gitlab/triage/filter_builders/base_filter_builder.rb +18 -0
  21. data/lib/gitlab/triage/filter_builders/multi_filter_builder.rb +20 -0
  22. data/lib/gitlab/triage/filter_builders/single_filter_builder.rb +13 -0
  23. data/lib/gitlab/triage/limiters/base_conditions_limiter.rb +65 -0
  24. data/lib/gitlab/triage/limiters/date_conditions_limiter.rb +63 -0
  25. data/lib/gitlab/triage/limiters/name_conditions_limiter.rb +30 -0
  26. data/lib/gitlab/triage/limiters/votes_conditions_limiter.rb +54 -0
  27. data/lib/gitlab/triage/network.rb +37 -0
  28. data/lib/gitlab/triage/network_adapters/httparty_adapter.rb +36 -0
  29. data/lib/gitlab/triage/network_adapters/test_adapter.rb +31 -0
  30. data/lib/gitlab/triage/retryable.rb +31 -0
  31. data/lib/gitlab/triage/ui.rb +15 -0
  32. data/lib/gitlab/triage/version.rb +5 -0
  33. data/policies.yml +232 -0
  34. metadata +160 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ff9f08acbd7e13f681bff4673c63d450b283f70a30d19a5831556b3d99bc3b49
4
+ data.tar.gz: 7ef092df664c16f65aecaf34ef1983ea25c2a9b611c0fcd33be96c3188624bdb
5
+ SHA512:
6
+ metadata.gz: 4587c4b294c332aab7d113d1925f0ee86512d02bcb8aabcaf59ad25f71674290ca361101094deb339a03f6e296ac0fd46142a6a1b5c548e6282efa2cedf68906
7
+ data.tar.gz: 786ad737d5891758591b4d78533b25f3aff7993c2a235e419603d8a5bcd01e18ae138514e7e73f7827126f6cf4ae94aa58225eb7b9029b8f7874aab8a36ed1a8
@@ -0,0 +1,19 @@
1
+ ---
2
+ engines:
3
+ bundler-audit:
4
+ enabled: true
5
+ duplication:
6
+ enabled: true
7
+ config:
8
+ languages:
9
+ - ruby
10
+ rubocop-gitlab:
11
+ enabled: true
12
+ ratings:
13
+ paths:
14
+ - Gemfile.lock
15
+ - "**.rb"
16
+ exclude_paths:
17
+ - spec/
18
+ - vendor/
19
+ - tmp/
@@ -0,0 +1,15 @@
1
+ /.DS_Store
2
+ /vendor/
3
+ /.rspec
4
+ /.bundle/
5
+ /.yardoc
6
+ /Gemfile.lock
7
+ /_yardoc/
8
+ /coverage/
9
+ /doc/
10
+ /pkg/
11
+ /spec/reports/
12
+ /tmp/
13
+
14
+ # rspec failure tracking
15
+ .rspec_status
@@ -0,0 +1,101 @@
1
+ image: ruby:2.4
2
+
3
+ stages:
4
+ - prepare
5
+ - test
6
+ - process_rules
7
+
8
+ .default-cache-config: &default-cache-config
9
+ key: "ruby-2.4"
10
+ paths:
11
+ - vendor/cache/
12
+ - Gemfile.lock
13
+
14
+ .pull-cache: &pull-cache
15
+ cache:
16
+ <<: *default-cache-config
17
+ policy: pull
18
+
19
+ before_script:
20
+ - gem install bundler
21
+ - bundle --version
22
+ - bundle install --jobs $(nproc) --retry 3 --quiet
23
+
24
+ setup-test-env:
25
+ stage: prepare
26
+ script:
27
+ - echo "All set!"
28
+ cache:
29
+ <<: *default-cache-config
30
+ artifacts:
31
+ paths:
32
+ - vendor/cache/
33
+ - Gemfile.lock
34
+
35
+ styles:
36
+ stage: test
37
+ script:
38
+ - bundle exec rubocop
39
+ except:
40
+ - schedules
41
+ <<: *pull-cache
42
+
43
+ specs:
44
+ stage: test
45
+ script:
46
+ - bundle exec rake spec
47
+ <<: *pull-cache
48
+
49
+ build:
50
+ stage: test
51
+ script:
52
+ - bundle exec rake build
53
+ - bundle exec rake clobber
54
+ except:
55
+ - schedules
56
+ <<: *pull-cache
57
+
58
+ codequality:
59
+ image: docker:latest
60
+ stage: test
61
+ variables:
62
+ DOCKER_DRIVER: overlay
63
+ services:
64
+ - docker:dind
65
+ before_script: []
66
+ script:
67
+ - docker run
68
+ --env CODECLIMATE_CODE="$PWD"
69
+ --volume "$PWD":/code
70
+ --volume /var/run/docker.sock:/var/run/docker.sock
71
+ --volume /tmp/cc:/tmp/cc
72
+ dev.gitlab.org:5005/gitlab/gitlab-build-images:gitlab-codeclimate
73
+ analyze -f json > raw_codeclimate.json
74
+ - cat raw_codeclimate.json | docker run -i stedolan/jq -c 'map({check_name,fingerprint,location})' > codeclimate.json
75
+ artifacts:
76
+ paths:
77
+ - codeclimate.json
78
+ except:
79
+ - schedules
80
+ <<: *pull-cache
81
+
82
+ dry-run:triage:
83
+ stage: test
84
+ script:
85
+ - bundle exec bin/gitlab-triage --dry-run --token $API_TOKEN --policies-file policies.yml --project-id gitlab-org/triage
86
+ <<: *pull-cache
87
+
88
+ dry-run:gilab-ce:
89
+ stage: process_rules
90
+ script:
91
+ - bundle exec bin/gitlab-triage --dry-run --token $API_TOKEN --policies-file policies.yml --project-id gitlab-org/gitlab-ce
92
+ when: manual
93
+ <<: *pull-cache
94
+
95
+ results:
96
+ stage: process_rules
97
+ script:
98
+ - bundle exec bin/gitlab-triage --token $API_TOKEN --policies-file policies.yml --project-id gitlab-org/gitlab-ce
99
+ only:
100
+ - schedules
101
+ <<: *pull-cache
@@ -0,0 +1,32 @@
1
+ ### Policy title
2
+
3
+ ( add a title to accurately describe the policy that you are referring to )
4
+
5
+ ### New Policy/Policy Change/Policy Removal
6
+
7
+ ( declare the type of policy change this is )
8
+
9
+ ### Issues or Merge Requests Policy?
10
+
11
+ Issues/Merge Requests/both
12
+
13
+ ### Policy Conditions
14
+
15
+ ( declare the conditions for the related policy )
16
+
17
+ #### Example
18
+
19
+ - Label: bug
20
+ - not updated for over 6 months
21
+ - no associated milestone (unscheduled)
22
+ - state: open
23
+
24
+ ### Policy Actions
25
+
26
+ ( declare the actions for the related policy )
27
+
28
+ #### Example
29
+
30
+ - Add a comment
31
+ - Mention @markglenfletcher
32
+ - Label: "awaiting feedback" "auto updated"
@@ -0,0 +1,6 @@
1
+ inherit_gem:
2
+ gitlab-styles:
3
+ - rubocop-default.yml
4
+
5
+ Rails/Output:
6
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gitlab-rubocop.gemspec
4
+ gemspec
@@ -0,0 +1,70 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ ## Uncomment and set this to only include directories you want to watch
5
+ # directories %w(app lib config test spec features) \
6
+ # .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
7
+
8
+ ## Note: if you are using the `directories` clause above and you are not
9
+ ## watching the project directory ('.'), then you will want to move
10
+ ## the Guardfile to a watched dir and symlink it back, e.g.
11
+ #
12
+ # $ mkdir config
13
+ # $ mv Guardfile config/
14
+ # $ ln -s config/Guardfile .
15
+ #
16
+ # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
17
+
18
+ # Note: The cmd option is now required due to the increasing number of ways
19
+ # rspec may be run, below are examples of the most common uses.
20
+ # * bundler: 'bundle exec rspec'
21
+ # * bundler binstubs: 'bin/rspec'
22
+ # * spring: 'bin/rspec' (This will use spring if running and you have
23
+ # installed the spring binstubs per the docs)
24
+ # * zeus: 'zeus rspec' (requires the server to be started separately)
25
+ # * 'just' rspec: 'rspec'
26
+
27
+ guard :rspec, cmd: "bundle exec rspec" do
28
+ require "guard/rspec/dsl"
29
+ dsl = Guard::RSpec::Dsl.new(self)
30
+
31
+ # Feel free to open issues for suggestions and improvements
32
+
33
+ # RSpec files
34
+ rspec = dsl.rspec
35
+ watch(rspec.spec_helper) { rspec.spec_dir }
36
+ watch(rspec.spec_support) { rspec.spec_dir }
37
+ watch(rspec.spec_files)
38
+
39
+ # Ruby files
40
+ ruby = dsl.ruby
41
+ dsl.watch_spec_files_for(ruby.lib_files)
42
+
43
+ # Rails files
44
+ rails = dsl.rails(view_extensions: %w[erb haml slim])
45
+ dsl.watch_spec_files_for(rails.app_files)
46
+ dsl.watch_spec_files_for(rails.views)
47
+
48
+ watch(rails.controllers) do |m|
49
+ [
50
+ rspec.spec.call("routing/#{m[1]}_routing"),
51
+ rspec.spec.call("controllers/#{m[1]}_controller"),
52
+ rspec.spec.call("acceptance/#{m[1]}")
53
+ ]
54
+ end
55
+
56
+ # Rails config changes
57
+ watch(rails.spec_helper) { rspec.spec_dir }
58
+ watch(rails.routes) { "#{rspec.spec_dir}/routing" }
59
+ watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
60
+
61
+ # Capybara features specs
62
+ watch(rails.view_dirs) { |m| rspec.spec.call("features/#{m[1]}") }
63
+ watch(rails.layouts) { |m| rspec.spec.call("features/#{m[1]}") }
64
+
65
+ # Turnip features and steps
66
+ watch(%r{^spec/acceptance/(.+)\.feature$})
67
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
68
+ Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
69
+ end
70
+ end
@@ -0,0 +1,13 @@
1
+ [![pipeline status](https://gitlab.com/gitlab-org/triage/badges/master/pipeline.svg)](https://gitlab.com/gitlab-org/triage/commits/master)
2
+
3
+ ## GitLab Triage Project
4
+
5
+ This project contains scripts used for triaging Issues and Merge Requests in [GitLab-CE Project](https://gitlab.com/gitlab-org/gitlab-ce) projects and enforcing our Issue Triage policies as well of generating data related to triaging issues more effectively.
6
+ The scripts found here may be useful for triaging issues in other projects too.
7
+
8
+ - We define the policies in code in a public project where those interested can raise issues surrounding our policies.
9
+ - We use scheduled pipelines to run the scripts to enforce our policies on a daily basis.
10
+
11
+ ## Suggesting new policies or suggesting changes to policies
12
+
13
+ Please feel free to [open an issue](https://gitlab.com/gitlab-org/triage/issues/new) about creating, editing or deleting a policy. Please select the policy issue template when creating an issue.
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'yaml'
5
+ require_relative '../lib/gitlab/triage/engine'
6
+
7
+ Options = Struct.new(
8
+ :dry_run,
9
+ :policies_file,
10
+ :project_id,
11
+ :token,
12
+ :debug
13
+ )
14
+
15
+ class TriageOptionParser
16
+ class << self
17
+ def parse(argv)
18
+ options = Options.new
19
+
20
+ parser = OptionParser.new do |opts|
21
+ opts.banner = "Usage: #{__FILE__} [options]\n\n"
22
+
23
+ opts.on('-n', '--dry-run', "Don't actually update anything, just print") do |value|
24
+ options.dry_run = value
25
+ end
26
+
27
+ opts.on('-f', '--policies-file [string]', String, 'A valid policies YML file') do |value|
28
+ options.policies_file = value
29
+ end
30
+
31
+ opts.on('-p', '--project-id [string]', String, 'A project ID or path') do |value|
32
+ options.project_id = value
33
+ end
34
+
35
+ opts.on('-t', '--token [string]', String, 'A valid API token') do |value|
36
+ options.token = value
37
+ end
38
+
39
+ opts.on('-d', '--debug', 'Print debug information') do |value|
40
+ options.debug = value
41
+ end
42
+
43
+ opts.on('-h', '--help', 'Print help message') do
44
+ $stdout.puts opts
45
+ exit
46
+ end
47
+ end
48
+
49
+ parser.parse!(argv)
50
+
51
+ options
52
+ end
53
+ end
54
+ end
55
+
56
+ options = TriageOptionParser.parse(ARGV)
57
+
58
+ policies_file = options.policies_file || '.triage-policies.yml'
59
+ policies = HashWithIndifferentAccess.new(YAML.load_file(policies_file))
60
+
61
+ Gitlab::Triage::Engine
62
+ .new(policies: policies, options: options)
63
+ .perform
@@ -0,0 +1,29 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'gitlab/triage/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'gitlab-triage'
7
+ spec.version = Gitlab::Triage::VERSION
8
+ spec.authors = ['GitLab']
9
+ spec.email = ['remy@rymai.me']
10
+
11
+ spec.summary = 'GitLab triage automation project.'
12
+ spec.homepage = 'https://gitlab.com/gitlab-org/triage'
13
+ spec.license = 'MIT'
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
16
+ f.match(%r{^(test|spec|features)/})
17
+ end
18
+ spec.bindir = 'exe'
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_dependency 'activesupport', '~> 5.1'
23
+ spec.add_dependency 'httparty', '~> 0.15'
24
+
25
+ spec.add_development_dependency 'bundler', '~> 1.15'
26
+ spec.add_development_dependency 'gitlab-styles', '~> 2.1'
27
+ spec.add_development_dependency 'rake', '~> 10.0'
28
+ spec.add_development_dependency 'rspec', '~> 3.0'
29
+ end
@@ -0,0 +1,6 @@
1
+ require 'gitlab/triage/version'
2
+
3
+ module Gitlab
4
+ module Triage
5
+ end
6
+ end
@@ -0,0 +1,32 @@
1
+ module Gitlab
2
+ module Triage
3
+ module CommandBuilders
4
+ class BaseCommandBuilder
5
+ def initialize(items)
6
+ @items = [items].flatten
7
+ @items.delete('')
8
+ end
9
+
10
+ def build_command
11
+ if @items.any?
12
+ [slash_command_string, content_string].compact.join(separator)
13
+ else
14
+ ""
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def separator
21
+ ' '
22
+ end
23
+
24
+ def content_string
25
+ @items.map do |item|
26
+ format_item(item)
27
+ end.join(separator)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,19 @@
1
+ require_relative 'base_command_builder'
2
+
3
+ module Gitlab
4
+ module Triage
5
+ module CommandBuilders
6
+ class CcCommandBuilder < BaseCommandBuilder
7
+ private
8
+
9
+ def slash_command_string
10
+ "/cc"
11
+ end
12
+
13
+ def format_item(item)
14
+ "@#{item}"
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,23 @@
1
+ require_relative 'base_command_builder'
2
+
3
+ module Gitlab
4
+ module Triage
5
+ module CommandBuilders
6
+ class CommentCommandBuilder < BaseCommandBuilder
7
+ private
8
+
9
+ def separator
10
+ "\n\n"
11
+ end
12
+
13
+ def slash_command_string
14
+ nil
15
+ end
16
+
17
+ def format_item(item)
18
+ item
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end