owners 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 03249f63f81c9db5877a0f55d0562c78e725afc6
4
- data.tar.gz: 4cc529092d6d620a6cc1c652c819f9d7b63d662f
3
+ metadata.gz: 65952d9a4159c6a54c705d6a4d52a251a34eacb7
4
+ data.tar.gz: d414a754b03b3549b017bbe3cff45ce511f69487
5
5
  SHA512:
6
- metadata.gz: ff1c532d637a42f59b985764d90f686629ac3be3fefc8bca062eda6be54f141ca599f86c88aedc6b6e22d5ff940b9a6e20c7ac236bbfc3015150a3a2d50123e7
7
- data.tar.gz: c6fe901e8fe7467cb8eda35f12d6d2d468e4c0b8a2999c935d8e092c57de18339926834202490fa6f2e191bdf1791a40b7a7e243caf6a953c57b812653b7e525
6
+ metadata.gz: 255d1ef9d4f7cf7c984d194e8224bc44c02ec72a26adaa2731955990d556bb111d306924675cd5b0a95cae364fb9738105474cc476774c93e675288a194bb719
7
+ data.tar.gz: 64a897f374262fb422aef1ea8181ae28ac4c8181318fc05db1a41cee6015626b7c09a5b767bd7df89d1fe705c757eaf4989bceaca9f51d77cadcca7f2c92bb4e
@@ -0,0 +1,11 @@
1
+ addons:
2
+ code_climate:
3
+ repo_token: ca03d82be038f1e592be540bc81030c2cc69101d13f99acfd1889bbd47d17824
4
+
5
+ install: bundle install --jobs 3 --retry 3
6
+
7
+ rvm:
8
+ - 2.0.0
9
+ - ruby-head
10
+
11
+ script: bundle exec rspec
data/Gemfile CHANGED
@@ -1,5 +1,5 @@
1
- source 'https://www.rubygems.org'
1
+ source "https://www.rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'codeclimate-test-reporter'
5
+ gem "codeclimate-test-reporter"
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Build Status](https://secure.travis-ci.org/shuber/owners.svg)](http://travis-ci.org/shuber/owners) [![Code Climate](https://codeclimate.com/github/shuber/owners/badges/gpa.svg)](https://codeclimate.com/github/shuber/owners) [![Coverage](https://codeclimate.com/github/shuber/owners/badges/coverage.svg)](https://codeclimate.com/github/shuber/owners) [![Gem Version](https://badge.fury.io/rb/owners.svg)](http://badge.fury.io/rb/owners)
4
4
 
5
- Take ownership of your code
5
+ Take ownership of your code.
6
6
 
7
7
 
8
8
  ## Installation
@@ -16,7 +16,7 @@ gem install owners
16
16
 
17
17
  Define an `OWNERS` file in any directory within your repository. This file should contain a newline separated list of subscribers to notify when files within the directory have changed. The `OWNERS` files are searched recursively up the tree to make organizing owners more convenient.
18
18
 
19
- Subscribers can be anything that suits your needs e.g. emails, GitHub handles, or Slack channels.
19
+ Subscribers can be anything that suits your needs e.g. emails, GitHub handles, Slack channels, etc.
20
20
 
21
21
  ```
22
22
  bob@your-org.com
@@ -34,18 +34,20 @@ The `OWNERS` file also supports limiting paths with regular expressions or exact
34
34
  bob@demo.com lib/bobs_special_file.rb
35
35
  ```
36
36
 
37
- Once your `OWNERS` files are defined, you can search for a list of owners by calling `Owners.for` with a list of paths e.g. output from `git diff --name-only`
37
+ Once your `OWNERS` files are defined, you can search for a list of owners by calling `Owners.for` with a list of paths e.g. output from `git diff --name-only`.
38
38
 
39
39
  ```ruby
40
40
  Owners.for(".env", "app/controllers/posts_controller.rb", "app/models/user.rb")
41
41
  ```
42
42
 
43
- This method returns a unique array of all the owners who have subscribed to changes for the specified files.
43
+ This method returns a unique array of all the owners who have subscribed to changes for the specified files. These subscribers can then be notified however you see fit!
44
44
 
45
45
  ## API
46
46
 
47
47
  [YARD Documentation](http://www.rubydoc.info/github/shuber/owners)
48
48
 
49
+ * `Owners.file`
50
+ * `Owners.file=`
49
51
  * `Owners.for`
50
52
 
51
53
 
@@ -1,10 +1,29 @@
1
- require 'owners/config'
2
- require 'owners/path'
3
- require 'owners/search'
4
- require 'owners/version'
1
+ require "pathname"
2
+ require "set"
3
+ require "owners/config"
4
+ require "owners/search"
5
+ require "owners/tree"
6
+ require "owners/version"
5
7
 
6
8
  module Owners
7
- def self.for(*paths)
8
- Search.new(paths).owners
9
+ class << self
10
+ # @api public
11
+ attr_writer :file
12
+
13
+ # The name of the file used to store ownership
14
+ # subscriptions. Defaults to OWNERS.
15
+ #
16
+ # @api public
17
+ def file
18
+ @file ||= "OWNERS"
19
+ end
20
+
21
+ # Accepts a list of file paths and returns an array of
22
+ # owners that have subscribed to the specified files.
23
+ #
24
+ # @api public
25
+ def for(*files)
26
+ Search.new(files).owners
27
+ end
9
28
  end
10
29
  end
@@ -1,22 +1,32 @@
1
1
  module Owners
2
+ # Parses an OWNERS file and returns an array of owners
3
+ # that have subscribed to a specified file path.
4
+ #
5
+ # @api private
2
6
  class Config
3
- attr_reader :root
4
-
5
7
  def initialize(file)
6
- @config = File.read(file)
7
- @root = File.dirname(file)
8
+ @config = file.read
9
+ @root = file.dirname.to_s
8
10
  end
9
11
 
10
- def owners
11
- subscriptions.each_with_object({}) do |line, hash|
12
- owner, path = line.split(/\s+/, 2).push('.*')
13
- hash[owner] ||= []
14
- hash[owner] << Regexp.new(path)
12
+ def owners(path)
13
+ if path.start_with?(@root)
14
+ relative = path.sub("#{@root}/", "")
15
+
16
+ search do |subscription, results|
17
+ owner, pattern = subscription.split(/\s+/, 2)
18
+ regex = Regexp.new(pattern || ".*")
19
+ results << owner if regex =~ relative
20
+ end
15
21
  end
16
22
  end
17
23
 
18
24
  private
19
25
 
26
+ def search(&block)
27
+ subscriptions.each_with_object([], &block)
28
+ end
29
+
20
30
  def subscriptions
21
31
  @config.split("\n").reject(&:empty?)
22
32
  end
@@ -1,17 +1,44 @@
1
1
  module Owners
2
+ # Accepts an array of file paths and returns an array of
3
+ # owners that have subscribed to the specified files.
4
+ #
5
+ # @api private
2
6
  class Search
3
- def initialize(paths)
4
- @paths = paths
7
+ def initialize(files)
8
+ @files = files
5
9
  end
6
10
 
7
11
  def owners
8
- paths.flat_map(&:owners).flatten.uniq.sort
12
+ search do |(path, config), results|
13
+ owners = config.owners(path.to_s)
14
+ results.merge(owners) if owners
15
+ end
9
16
  end
10
17
 
11
18
  private
12
19
 
20
+ def search(&block)
21
+ attempts.each_with_object(SortedSet.new, &block).to_a
22
+ end
23
+
24
+ def attempts
25
+ paths.product(configs)
26
+ end
27
+
28
+ def configs
29
+ subscriptions.map { |file| Config.new(file) }
30
+ end
31
+
32
+ def subscriptions
33
+ trees.flat_map(&:owner_files).uniq
34
+ end
35
+
36
+ def trees
37
+ paths.map { |path| Tree.new(path) }
38
+ end
39
+
13
40
  def paths
14
- @paths.map { |path| Path.new(path) }
41
+ @files.map { |file| Pathname.new(file) }
15
42
  end
16
43
  end
17
44
  end
@@ -0,0 +1,32 @@
1
+ module Owners
2
+ # Traverses up the directory tree starting at a specified
3
+ # file and returns an array of all OWNERS files.
4
+ #
5
+ # @api private
6
+ class Tree
7
+ def initialize(file)
8
+ @file = file
9
+ end
10
+
11
+ def owner_files
12
+ parents.each_with_object([]) do |parent, files|
13
+ config = parent.join(Owners.file)
14
+ files << config if config.file?
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def parents
21
+ parents = []
22
+ file = @file
23
+
24
+ until file == file.dirname
25
+ file = file.dirname
26
+ parents << file
27
+ end
28
+
29
+ parents
30
+ end
31
+ end
32
+ end
@@ -1,3 +1,3 @@
1
1
  module Owners
2
- VERSION = '0.0.0'
2
+ VERSION = "0.0.1"
3
3
  end
@@ -1,19 +1,19 @@
1
- require File.expand_path('../lib/owners/version', __FILE__)
1
+ require File.expand_path("../lib/owners/version", __FILE__)
2
2
 
3
3
  Gem::Specification.new do |s|
4
- s.author = 'Sean Huber'
5
- s.email = 'github@shuber.io'
4
+ s.author = "Sean Huber"
5
+ s.email = "github@shuber.io"
6
6
  s.extra_rdoc_files = %w(LICENSE)
7
7
  s.files = `git ls-files`.split("\n")
8
- s.homepage = 'https://github.com/shuber/owners'
9
- s.license = 'MIT'
10
- s.name = 'owners'
8
+ s.homepage = "https://github.com/shuber/owners"
9
+ s.license = "MIT"
10
+ s.name = "owners"
11
11
  s.rdoc_options = %w(--charset=UTF-8 --inline-source --line-numbers --main README.md)
12
12
  s.require_paths = %w(lib)
13
- s.required_ruby_version = '>= 2.0.0'
14
- s.summary = 'Take ownership of your code'
13
+ s.required_ruby_version = ">= 2.0.0"
14
+ s.summary = "Take ownership of your code"
15
15
  s.test_files = `git ls-files -- spec/*`.split("\n")
16
16
  s.version = Owners::VERSION
17
17
 
18
- s.add_development_dependency 'rspec'
18
+ s.add_development_dependency "rspec"
19
19
  end
@@ -1,47 +1,47 @@
1
1
  RSpec.describe Owners do
2
- describe '.for' do
2
+ describe ".for" do
3
3
  subject { described_class.for(*paths) }
4
4
 
5
- context 'with one path' do
6
- let(:paths) { ['example/app/controllers/users_controller.rb'] }
5
+ context "with one path" do
6
+ let(:paths) { ["example/app/controllers/users_controller.rb"] }
7
7
 
8
- it 'parses owners correctly' do
9
- expect(subject).to eq(['@org/auth', '@org/blog'])
8
+ it "parses owners correctly" do
9
+ expect(subject).to eq(["@org/auth", "@org/blog"])
10
10
  end
11
11
  end
12
12
 
13
- context 'with multiple paths' do
13
+ context "with multiple paths" do
14
14
  let(:paths) {[
15
- 'example/app/controllers/posts_controller.rb',
16
- 'example/app/models/user.rb',
15
+ "example/app/controllers/posts_controller.rb",
16
+ "example/app/models/user.rb",
17
17
  ]}
18
18
 
19
- it 'parses owners correctly' do
20
- expect(subject).to eq(['@org/auth', '@org/blog', 'data@example.com'])
19
+ it "parses owners correctly" do
20
+ expect(subject).to eq(["@org/auth", "@org/blog", "data@example.com"])
21
21
  end
22
22
  end
23
23
 
24
- context 'with no matches' do
25
- let(:paths) { ['some-path-without-owners'] }
24
+ context "with no matches" do
25
+ let(:paths) { ["some-path-without-owners"] }
26
26
 
27
- it 'parses owners correctly' do
27
+ it "parses owners correctly" do
28
28
  expect(subject).to be_empty
29
29
  end
30
30
  end
31
31
 
32
- context 'with a regex matcher' do
33
- let(:paths) { ['example/app/models/blog.rb'] }
32
+ context "with a regex matcher" do
33
+ let(:paths) { ["example/app/models/blog.rb"] }
34
34
 
35
- it 'parses owners correctly' do
36
- expect(subject).to eq(['@blogger', '@org/blog', 'data@example.com'])
35
+ it "parses owners correctly" do
36
+ expect(subject).to eq(["@blogger", "@org/blog", "data@example.com"])
37
37
  end
38
38
  end
39
39
 
40
- context 'with a rule containing whitespace' do
41
- let(:paths) { ['example/app/models/post.rb'] }
40
+ context "with a rule containing whitespace" do
41
+ let(:paths) { ["example/app/models/post.rb"] }
42
42
 
43
- it 'parses owners correctly' do
44
- expect(subject).to eq(['@org/blog', '@whitespace', 'data@example.com'])
43
+ it "parses owners correctly" do
44
+ expect(subject).to eq(["@org/blog", "@whitespace", "data@example.com"])
45
45
  end
46
46
  end
47
47
  end
@@ -1,12 +1,12 @@
1
- if ENV['CODECLIMATE_REPO_TOKEN']
2
- require 'codeclimate-test-reporter'
1
+ if ENV["CODECLIMATE_REPO_TOKEN"]
2
+ require "codeclimate-test-reporter"
3
3
  CodeClimate::TestReporter.start
4
4
  else
5
- require 'simplecov'
6
- SimpleCov.start { add_filter('/vendor/bundle/') }
5
+ require "simplecov"
6
+ SimpleCov.start { add_filter("/vendor/bundle/") }
7
7
  end
8
8
 
9
- require File.expand_path('../../lib/owners', __FILE__)
9
+ require File.expand_path("../../lib/owners", __FILE__)
10
10
 
11
11
  RSpec.configure do |config|
12
12
  config.filter_run :focus
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: owners
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Huber
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-21 00:00:00.000000000 Z
11
+ date: 2015-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -33,6 +33,7 @@ extra_rdoc_files:
33
33
  files:
34
34
  - ".gitignore"
35
35
  - ".rspec"
36
+ - ".travis.yml"
36
37
  - Gemfile
37
38
  - Gemfile.lock
38
39
  - LICENSE
@@ -47,9 +48,8 @@ files:
47
48
  - example/app/models/user.rb
48
49
  - lib/owners.rb
49
50
  - lib/owners/config.rb
50
- - lib/owners/core_ext
51
- - lib/owners/path.rb
52
51
  - lib/owners/search.rb
52
+ - lib/owners/tree.rb
53
53
  - lib/owners/version.rb
54
54
  - owners.gemspec
55
55
  - spec/owners_spec.rb
File without changes
@@ -1,41 +0,0 @@
1
- module Owners
2
- class Path
3
- CONFIG = 'OWNERS'
4
-
5
- def initialize(file)
6
- @file = file
7
- end
8
-
9
- def owners
10
- configs.each_with_object([]) do |config, owners|
11
- path = @file.sub("#{config.root}/", '')
12
-
13
- config.owners.each do |owner, regexes|
14
- regexes.each do |regex|
15
- if path =~ regex
16
- owners << owner
17
- end
18
- end
19
- end
20
- end
21
- end
22
-
23
- private
24
-
25
- def configs
26
- configs = []
27
- file = @file
28
-
29
- until ['.', '/'].include?(file)
30
- file = File.dirname(file)
31
- config = File.join(file, CONFIG)
32
-
33
- if File.exists?(config) && !File.directory?(config)
34
- configs << Config.new(config)
35
- end
36
- end
37
-
38
- configs
39
- end
40
- end
41
- end