owners 0.0.0 → 0.0.1
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 +4 -4
- data/.travis.yml +11 -0
- data/Gemfile +2 -2
- data/README.md +6 -4
- data/lib/owners.rb +25 -6
- data/lib/owners/config.rb +19 -9
- data/lib/owners/search.rb +31 -4
- data/lib/owners/tree.rb +32 -0
- data/lib/owners/version.rb +1 -1
- data/owners.gemspec +9 -9
- data/spec/owners_spec.rb +21 -21
- data/spec/spec_helper.rb +5 -5
- metadata +4 -4
- data/lib/owners/core_ext +0 -0
- data/lib/owners/path.rb +0 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 65952d9a4159c6a54c705d6a4d52a251a34eacb7
|
4
|
+
data.tar.gz: d414a754b03b3549b017bbe3cff45ce511f69487
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 255d1ef9d4f7cf7c984d194e8224bc44c02ec72a26adaa2731955990d556bb111d306924675cd5b0a95cae364fb9738105474cc476774c93e675288a194bb719
|
7
|
+
data.tar.gz: 64a897f374262fb422aef1ea8181ae28ac4c8181318fc05db1a41cee6015626b7c09a5b767bd7df89d1fe705c757eaf4989bceaca9f51d77cadcca7f2c92bb4e
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
[](http://travis-ci.org/shuber/owners) [](https://codeclimate.com/github/shuber/owners) [](https://codeclimate.com/github/shuber/owners) [](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,
|
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
|
|
data/lib/owners.rb
CHANGED
@@ -1,10 +1,29 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
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
|
-
|
8
|
-
|
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
|
data/lib/owners/config.rb
CHANGED
@@ -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 =
|
7
|
-
@root =
|
8
|
+
@config = file.read
|
9
|
+
@root = file.dirname.to_s
|
8
10
|
end
|
9
11
|
|
10
|
-
def owners
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
data/lib/owners/search.rb
CHANGED
@@ -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(
|
4
|
-
@
|
7
|
+
def initialize(files)
|
8
|
+
@files = files
|
5
9
|
end
|
6
10
|
|
7
11
|
def owners
|
8
|
-
|
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
|
-
@
|
41
|
+
@files.map { |file| Pathname.new(file) }
|
15
42
|
end
|
16
43
|
end
|
17
44
|
end
|
data/lib/owners/tree.rb
ADDED
@@ -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
|
data/lib/owners/version.rb
CHANGED
data/owners.gemspec
CHANGED
@@ -1,19 +1,19 @@
|
|
1
|
-
require File.expand_path(
|
1
|
+
require File.expand_path("../lib/owners/version", __FILE__)
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
|
-
s.author =
|
5
|
-
s.email =
|
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 =
|
9
|
-
s.license =
|
10
|
-
s.name =
|
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 =
|
14
|
-
s.summary =
|
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
|
18
|
+
s.add_development_dependency "rspec"
|
19
19
|
end
|
data/spec/owners_spec.rb
CHANGED
@@ -1,47 +1,47 @@
|
|
1
1
|
RSpec.describe Owners do
|
2
|
-
describe
|
2
|
+
describe ".for" do
|
3
3
|
subject { described_class.for(*paths) }
|
4
4
|
|
5
|
-
context
|
6
|
-
let(:paths) { [
|
5
|
+
context "with one path" do
|
6
|
+
let(:paths) { ["example/app/controllers/users_controller.rb"] }
|
7
7
|
|
8
|
-
it
|
9
|
-
expect(subject).to eq([
|
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
|
13
|
+
context "with multiple paths" do
|
14
14
|
let(:paths) {[
|
15
|
-
|
16
|
-
|
15
|
+
"example/app/controllers/posts_controller.rb",
|
16
|
+
"example/app/models/user.rb",
|
17
17
|
]}
|
18
18
|
|
19
|
-
it
|
20
|
-
expect(subject).to eq([
|
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
|
25
|
-
let(:paths) { [
|
24
|
+
context "with no matches" do
|
25
|
+
let(:paths) { ["some-path-without-owners"] }
|
26
26
|
|
27
|
-
it
|
27
|
+
it "parses owners correctly" do
|
28
28
|
expect(subject).to be_empty
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
context
|
33
|
-
let(:paths) { [
|
32
|
+
context "with a regex matcher" do
|
33
|
+
let(:paths) { ["example/app/models/blog.rb"] }
|
34
34
|
|
35
|
-
it
|
36
|
-
expect(subject).to eq([
|
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
|
41
|
-
let(:paths) { [
|
40
|
+
context "with a rule containing whitespace" do
|
41
|
+
let(:paths) { ["example/app/models/post.rb"] }
|
42
42
|
|
43
|
-
it
|
44
|
-
expect(subject).to eq([
|
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
|
data/spec/spec_helper.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
if ENV[
|
2
|
-
require
|
1
|
+
if ENV["CODECLIMATE_REPO_TOKEN"]
|
2
|
+
require "codeclimate-test-reporter"
|
3
3
|
CodeClimate::TestReporter.start
|
4
4
|
else
|
5
|
-
require
|
6
|
-
SimpleCov.start { add_filter(
|
5
|
+
require "simplecov"
|
6
|
+
SimpleCov.start { add_filter("/vendor/bundle/") }
|
7
7
|
end
|
8
8
|
|
9
|
-
require File.expand_path(
|
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.
|
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-
|
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
|
data/lib/owners/core_ext
DELETED
File without changes
|
data/lib/owners/path.rb
DELETED
@@ -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
|