ey_resolver 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.
@@ -0,0 +1,5 @@
1
+ class EY::Resolver
2
+ module Mock
3
+ require 'ey_resolver/mock/models'
4
+ end
5
+ end
@@ -0,0 +1,13 @@
1
+ module EY::Resolver::Mock
2
+ require 'ey_resolver/mock/models/user'
3
+ require 'ey_resolver/mock/models/account'
4
+ require 'ey_resolver/mock/models/app'
5
+ require 'ey_resolver/mock/models/environment'
6
+ require 'ey_resolver/mock/models/app_environment'
7
+
8
+ require 'dm-migrations'
9
+ require 'dm-aggregates'
10
+ DataMapper.setup(:default, "sqlite::memory:")
11
+ DataMapper.finalize
12
+ DataMapper.auto_migrate!
13
+ end
@@ -0,0 +1,12 @@
1
+ require 'dm-core'
2
+
3
+ class Account
4
+ include DataMapper::Resource
5
+
6
+ property :id, Serial
7
+ property :name, String
8
+
9
+ belongs_to :user
10
+ has n, :environments
11
+ has n, :apps
12
+ end
@@ -0,0 +1,18 @@
1
+ require 'gitable'
2
+ require 'dm-core'
3
+
4
+ class App
5
+ include DataMapper::Resource
6
+
7
+ property :id, Serial
8
+ property :name, String
9
+ property :repository_uri, String
10
+
11
+ belongs_to :account
12
+ has n, :app_environments
13
+ has n, :environments, :through => :app_environments
14
+
15
+ def gitable_uri
16
+ Gitable::URI.parse(repository_uri)
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ require 'dm-core'
2
+
3
+ class AppEnvironment
4
+ include DataMapper::Resource
5
+
6
+ property :id, Serial
7
+ property :app_id, Integer
8
+ property :environment_id, Integer
9
+
10
+ belongs_to :app
11
+ belongs_to :environment
12
+
13
+ def inspect
14
+ "#<AppEnvironment app:#{app.name} env:#{environment.name}>"
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ require 'dm-core'
2
+
3
+ class Environment
4
+ include DataMapper::Resource
5
+
6
+ property :id, Serial
7
+ property :name, String
8
+
9
+ belongs_to :account
10
+ has n, :app_environments
11
+ has n, :apps, :through => :app_environments
12
+
13
+ def inspect
14
+ "#<Environment name:#{name} account:#{account.name}>"
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ require 'dm-core'
2
+
3
+ class User
4
+ include DataMapper::Resource
5
+
6
+ property :id, Serial
7
+ property :name, String
8
+
9
+ has n, :accounts
10
+ end
@@ -0,0 +1,68 @@
1
+ require 'gitable'
2
+
3
+ class EY::Resolver
4
+ class Query
5
+
6
+ def initialize(params)
7
+ self.query = params
8
+ end
9
+
10
+ def account_name() query[:account_name] end
11
+ def app_name() query[:app_name] end
12
+ def environment_name() query[:environment_name] end
13
+ def remotes() query[:remotes] end
14
+
15
+ def count_matches(&block)
16
+ query.count(&block)
17
+ end
18
+
19
+ def app_constrained?
20
+ app_name || remotes
21
+ end
22
+
23
+ def app_unconstrained?
24
+ !app_constrained?
25
+ end
26
+
27
+ def env_constrained?
28
+ environment_name || app_name || remotes
29
+ end
30
+
31
+ def env_unconstrained?
32
+ !env_constrained?
33
+ end
34
+
35
+ # The only case where an unconstrained set would return a single record is if
36
+ # there is only one possible candidate. If we don't have an app name or a
37
+ # repository_uri at all, then how do we know it's the right one anyway?
38
+ def unconstrained?
39
+ query.all? { |k,v| v.nil? || v.empty? || v.to_s.empty? }
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :query
45
+
46
+ def query=(params)
47
+ @query = {}
48
+ params.each do |key,val|
49
+ if converted = convert_value(key,val)
50
+ @query[key.to_sym] = converted
51
+ end
52
+ end
53
+
54
+ @query.delete(:remotes) if @query[:app_name]
55
+ @query.freeze
56
+ end
57
+
58
+ def convert_value(key, val)
59
+ if key.to_sym == :remotes
60
+ return nil if val.nil? || val.empty?
61
+ val.reject {|uri| uri.to_s.empty? }.map { |uri| Gitable::URI.parse_when_valid(uri) }.compact
62
+ else
63
+ norm = val.to_s.gsub(/[^\w-]+/,'')
64
+ norm.empty? ? nil : norm
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,5 @@
1
+ module EY
2
+ class Resolver
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,120 @@
1
+ require 'spec_helper'
2
+
3
+ describe EY::Resolver::AppEnvResolver do
4
+
5
+ def account_resolver(*args)
6
+ EY::Resolver.account_resolver(user, to_query(args))
7
+ end
8
+
9
+ def accounts(*models)
10
+ models.map { |model| model[:account] }
11
+ end
12
+
13
+ before(:all) do
14
+ # More correct names, even though it doesn't matter
15
+ @ey = @production
16
+ @me = @me_dup
17
+ @no = @account
18
+ end
19
+
20
+ describe "#matches" do
21
+ it "return empty if the conditions are empty" do
22
+ account_resolver( ).matches.should == []
23
+ account_resolver(nil, nil, nil, []).matches.should == []
24
+ account_resolver('', '', '', [''] ).matches.should == []
25
+ end
26
+
27
+ it "returns empty when there is no account match" do
28
+ account_resolver('gibberish').matches.should == []
29
+ end
30
+
31
+ it "ignore app name if it doesn't match" do
32
+ account_resolver('me', 'bigapp').matches.should == accounts(@me)
33
+ end
34
+
35
+ it "finds account with no apps" do
36
+ account_resolver("no").matches.should == accounts(@no)
37
+ end
38
+
39
+ it "ignores environment" do
40
+ account_resolver(nil, 'big', 'gibberish').matches.should == accounts(@ey)
41
+ end
42
+
43
+ it "returns more matches when there is more than one match" do
44
+ account_resolver(nil, nil, nil, ["git://github.com/repo/dup.git"]).matches.should == accounts(@ey, @me)
45
+ account_resolver('e').matches.should == accounts(@ey, @me)
46
+ end
47
+
48
+ it "returns one deployment whene there is only one match" do
49
+ account_resolver('ey' ).matches.should == accounts(@ey)
50
+ account_resolver(nil, "bigapp").matches.should == accounts(@ey)
51
+ account_resolver(nil, "app" ).matches.should == accounts(@ey, @me)
52
+ account_resolver("ey", "app" ).matches.should == accounts(@ey)
53
+ account_resolver("me" ).matches.should == accounts(@me)
54
+ end
55
+
56
+ it "uses repo as a hint but doesn't require it" do
57
+ account_resolver("ey", nil, nil, ["git://github.com/repo/app.git"]).matches.should == accounts(@ey)
58
+ account_resolver("me", nil, nil, ["git://github.com/repo/big.git"]).matches.should == accounts(@me)
59
+ account_resolver("no", nil, nil, ["git://github.com/repo/hug.git", "git://github.com/repo/big.git"]).matches.should == accounts(@no)
60
+ end
61
+
62
+ it "doesn't care about case" do
63
+ account_resolver("EY", "big").matches.should == accounts(@ey)
64
+ account_resolver("ey", "BiG").matches.should == accounts(@ey)
65
+ end
66
+
67
+ it "returns the match when an app is specified even when there is a repo" do
68
+ account_resolver("ey", "bigapp", nil, ["git://github.com/repo/app.git"]).matches.should == accounts(@ey)
69
+ end
70
+
71
+ it "returns the specific match even if there is a partial match" do
72
+ account_resolver('e', 'app').matches.should == accounts(@ey, @me)
73
+ account_resolver(nil, "app").matches.should == accounts(@ey, @me)
74
+ end
75
+
76
+ it "scopes searches under the correct account" do
77
+ account_resolver("ey", "dup").matches.should == accounts(@ey)
78
+ account_resolver("me", "dup").matches.should == accounts(@me)
79
+ account_resolver("ey", nil, nil, ["git://github.com/repo/dup.git"]).matches.should == accounts(@ey)
80
+ account_resolver("me", nil, nil, ["git://github.com/repo/dup.git"]).matches.should == accounts(@me)
81
+ end
82
+ end
83
+
84
+ describe "#errors" do
85
+ it "no account" do
86
+ account_resolver('gibberish', 'app', 'production').errors.should ==
87
+ [%|No account found matching "gibberish".|]
88
+ end
89
+
90
+ it "no app" do
91
+ account_resolver(nil, 'gibberish', 'app_dup').errors.should ==
92
+ [%|No application found matching "gibberish".|]
93
+ end
94
+
95
+ it "no env" do
96
+ account_resolver('ey', 'app', 'gibberish').errors.should ==
97
+ [%|No environment found matching "gibberish".|]
98
+ end
99
+
100
+ it "no account or app" do
101
+ account_resolver('gibberish', 'gibberish', nil).errors.should == [
102
+ %|No account found matching "gibberish".|,
103
+ %|No application found matching "gibberish".|,
104
+ ]
105
+ end
106
+
107
+ it "no account or app or env" do
108
+ account_resolver('gibberish', 'gibberish', 'gibberish').errors.should == [
109
+ %|No account found matching "gibberish".|,
110
+ %|No application found matching "gibberish".|,
111
+ %|No environment found matching "gibberish".|,
112
+ ]
113
+ end
114
+
115
+ it "repo not found" do
116
+ account_resolver(nil, nil, nil, ["git://fake.com/fake/fake.git"]).errors.should ==
117
+ [%|No application found matching remotes:\n\tgit://fake.com/fake/fake.git|]
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,159 @@
1
+ require 'spec_helper'
2
+
3
+ describe EY::Resolver::AppEnvResolver do
4
+
5
+ def app_env_resolver(*args)
6
+ EY::Resolver.app_env_resolver(user, to_query(args))
7
+ end
8
+
9
+ def app_envs(*models)
10
+ models.map { |model| model[:app_env] }
11
+ end
12
+
13
+ describe "#matches" do
14
+ it "raises if the conditions are empty" do
15
+ app_env_resolver( ).matches.should == []
16
+ app_env_resolver(nil, nil, nil, []).matches.should == []
17
+ app_env_resolver('', '', '', [''] ).matches.should == []
18
+ end
19
+
20
+ it "raises if the conditions do not include an app or remotes" do
21
+ app_env_resolver(nil, nil, 'app_dup' ).matches.should == []
22
+ app_env_resolver('ey', nil, nil ).matches.should == []
23
+ app_env_resolver('ey', nil, 'app_dup' ).matches.should == []
24
+ app_env_resolver('ey', nil, 'app_dup', []).matches.should == []
25
+ end
26
+
27
+ it "returns empty when there is no account match" do
28
+ app_env_resolver('gibberish', 'app', 'production').matches.should == []
29
+ end
30
+
31
+ it "returns empty when there is no app match" do
32
+ app_env_resolver(nil, 'gibberish', 'app_dup').matches.should == []
33
+ end
34
+
35
+ it "returns empty when there is no environment match" do
36
+ app_env_resolver(nil, 'app', 'gibberish').matches.should == []
37
+ end
38
+
39
+ it "returns empty when no matches" do
40
+ app_env_resolver(nil, 'bigapp', 'app_dup').matches.should == []
41
+ app_env_resolver(nil, nil, 'app_dup', ["git://github.com/repo/app.git"]).matches.should == []
42
+ end
43
+
44
+ it "returns more matches when there is more than one match" do
45
+ app_env_resolver(nil, "app", nil, nil ).matches.should == app_envs(@production, @staging)
46
+ app_env_resolver("ey", "app", nil, nil ).matches.should == app_envs(@production, @staging)
47
+ app_env_resolver(nil, nil, nil, ["git://github.com/repo/app.git"]).matches.should == app_envs(@production, @staging)
48
+ app_env_resolver(nil, nil, nil, ["git://github.com/repo/hug.git", "git://github.com/repo/big.git"]).matches.should == app_envs(@hugeprod, @big)
49
+ app_env_resolver(nil, nil, nil, ["git://github.com/repo/dup.git"]).matches.should == app_envs(@ey_dup, @sumo, @me_dup)
50
+ end
51
+
52
+ it "returns one deployment whene there is only one match" do
53
+ app_env_resolver("ey", "big", nil, nil ).matches.should == app_envs(@big)
54
+ app_env_resolver(nil, nil, 'production', ["git://github.com/repo/app.git"]).matches.should == app_envs(@production)
55
+ app_env_resolver(nil, 'app', "production", nil ).matches.should == app_envs(@production)
56
+ app_env_resolver(nil, nil, 'staging', ["git://github.com/repo/app.git"]).matches.should == app_envs(@staging)
57
+ app_env_resolver(nil, nil, nil, ["git://github.com/repo/big.git"]).matches.should == app_envs(@big)
58
+ app_env_resolver(nil, nil, 'bigapp', ["git://github.com/repo/hug.git", "git://github.com/repo/big.git"]).matches.should == app_envs(@big)
59
+ end
60
+
61
+ it "doesn't care about case" do
62
+ app_env_resolver("EY", "big").matches.should == app_envs(@big)
63
+ app_env_resolver("ey", "BiG").matches.should == app_envs(@big)
64
+ end
65
+
66
+ it "returns the match when an app is specified even when there is a repo" do
67
+ app_env_resolver("ey", "bigapp", nil, ["git://github.com/repo/app.git"]).matches.should == app_envs(@big)
68
+ end
69
+
70
+ it "returns the specific match even if there is a partial match" do
71
+ app_env_resolver(nil, 'app', 'app_staging').matches.should == app_envs(@staging)
72
+ app_env_resolver(nil, "app", "staging" ).matches.should == app_envs(@staging)
73
+ end
74
+
75
+ it "scopes searches under the correct account" do
76
+ app_env_resolver("ey", "dup", "dup", nil ).matches.should == app_envs(@ey_dup)
77
+ app_env_resolver("me", nil, "dup", ["git://github.com/repo/dup.git"]).matches.should == app_envs(@me_dup)
78
+ app_env_resolver("me", nil, nil, ["git://github.com/repo/dup.git"]).matches.should == app_envs(@me_dup)
79
+ app_env_resolver("me", "dup", nil, nil ).matches.should == app_envs(@me_dup)
80
+ end
81
+ end
82
+
83
+ describe "#errors" do
84
+
85
+ it "no constraints" do
86
+ app_env_resolver().errors.should ==
87
+ [%|Must search by account name, app name, remotes, or environment name.|]
88
+ end
89
+
90
+ it "no app constraints" do
91
+ app_env_resolver('ey').errors.should ==
92
+ [%|App name or repository remotes required.|]
93
+ end
94
+
95
+ it "no account" do
96
+ app_env_resolver('gibberish', 'app', 'production').errors.should ==
97
+ [%|No account found matching "gibberish".|]
98
+ end
99
+
100
+ it "no app" do
101
+ app_env_resolver(nil, 'gibberish', 'app_dup').errors.should ==
102
+ [%|No application found matching "gibberish".|]
103
+ end
104
+
105
+ it "app found, but not on account" do
106
+ app_env_resolver('no', 'bigapp', 'app_dup').errors.should == [
107
+ %|Application "bigapp" found, but does not exist in account "no".|,
108
+ %|Environment "app_dup" found, but does not exist in account "no".|,
109
+ ]
110
+ end
111
+
112
+ it "no env" do
113
+ app_env_resolver('ey', 'app', 'gibberish').errors.should ==
114
+ [%|No environment found matching "gibberish".|]
115
+ end
116
+
117
+ it "no env on account" do
118
+ app_env_resolver('me', 'other', 'production').errors.should ==
119
+ [%|Environment "production" found, but does not exist in account "me".|]
120
+ end
121
+
122
+ it "no account or app" do
123
+ app_env_resolver('gibberish', 'gibberish', nil).errors.should == [
124
+ %|No account found matching "gibberish".|,
125
+ %|No application found matching "gibberish".|,
126
+ ]
127
+ end
128
+
129
+ it "no account or app or env" do
130
+ app_env_resolver('gibberish', 'gibberish', 'gibberish').errors.should == [
131
+ %|No account found matching "gibberish".|,
132
+ %|No application found matching "gibberish".|,
133
+ %|No environment found matching "gibberish".|,
134
+ ]
135
+ end
136
+
137
+ it "repo not found" do
138
+ app_env_resolver(nil, nil, nil, ["git://fake.com/fake/fake.git"]).errors.should ==
139
+ [%|No application found matching remotes:\n\tgit://fake.com/fake/fake.git|]
140
+ end
141
+
142
+ it "repo not found in account" do
143
+ app_env_resolver('ey', nil, nil, ["git://github.com/repo/oth.git"]).errors.should ==
144
+ [%|Application "other" found, but does not exist in account "ey".|]
145
+ end
146
+
147
+ it "app and environment not associated" do
148
+ app_env_resolver('ey', 'bigapp', 'app_dup').errors.should ==
149
+ [%|Application "bigapp" and environment "app_dup" are not associated.|]
150
+ app_env_resolver(nil, nil, 'app_dup', ["git://github.com/repo/app.git"]).errors.should ==
151
+ [%|Application "app" and environment "app_dup" are not associated.|]
152
+ end
153
+
154
+ it "app (by repo) does not have an environment" do
155
+ app_env_resolver(nil, nil, nil, ["git://github.com/repo/noe.git"]).errors.should ==
156
+ [%|No environment found for applications matching remotes:\n\tgit://github.com/repo/noe.git|]
157
+ end
158
+ end
159
+ end