api_deploy 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/bitbucket.rb ADDED
@@ -0,0 +1,68 @@
1
+ class Bitbucket
2
+ include API
3
+ LIMIT=1000.to_s
4
+
5
+ HOOK_EXCLUSIONS = ['WSC','CM','YOMS']
6
+
7
+ def initialize
8
+ create_api( ConfigStore.bitbucket )
9
+ end
10
+
11
+ def projects
12
+ @projects ||= Project.get_all(self)
13
+ end
14
+
15
+ def set_master_branch_protected_on_all_projects
16
+ projects.map do |project|
17
+ project.repositories.map do |r|
18
+ r.set_master_branch_protected unless r.master_branch_protected?
19
+ end
20
+ end
21
+ end
22
+
23
+ def set_hook_status_on_all_projects(key,status,settings=nil)
24
+ projects.map do |project|
25
+ next if HOOK_EXCLUSIONS.include?(project.key)
26
+ project.set_hook_status(key, status, settings)
27
+ end
28
+ end
29
+
30
+ def remove_hooks_on_exclusions
31
+ projects.select {|p| HOOK_EXCLUSIONS.include? p.key }.each do |project|
32
+ [
33
+ 'org.christiangalsterer.stash-filehooks-plugin:filesize-hook',
34
+ "org.christiangalsterer.stash-filehooks-plugin:filename-hook",
35
+ ].each do |key|
36
+ project.set_hook_status(key, false)
37
+ end
38
+ end
39
+ end
40
+
41
+ def apply_restrictions
42
+ set_hook_status_on_all_projects(
43
+ "org.christiangalsterer.stash-filehooks-plugin:filesize-hook",
44
+ true,
45
+ {
46
+ "pattern-1"=>".*",
47
+ "size-1"=>"10485760",
48
+ "pattern-exclude-1"=>"",
49
+ "pattern-branches-1"=>""
50
+ }.to_json
51
+ )
52
+
53
+ set_hook_status_on_all_projects(
54
+ "org.christiangalsterer.stash-filehooks-plugin:filename-hook",
55
+ false,
56
+ {
57
+ "pattern"=>"\\.(h26.?|mp.?.?|avi|webm|flv|tar(\\..?.?.?)?|zip|7z|rar|exe|msi|rpm|deb)$",
58
+ "pattern-exclude"=>"",
59
+ "pattern-branches"=>""
60
+ }.to_json
61
+ )
62
+
63
+ set_master_branch_protected_on_all_projects
64
+
65
+ # cleanup TRAIN project
66
+ projects.detect {|p| p.key == 'TRAIN'}.move_all_repos_to_project('TOLD')
67
+ end
68
+ end
@@ -0,0 +1,34 @@
1
+ class Project
2
+ include API
3
+ LIMIT=1000.to_s
4
+
5
+ def self.get_all(server)
6
+ data = server.request(:get, "rest/api/1.0/projects?limit=#{LIMIT}")
7
+ data['values'].map {|p| new(server,p) }
8
+ end
9
+
10
+ attr_reader :name, :key
11
+
12
+ def initialize(server,data)
13
+ @bb = server
14
+ @name = data['name']
15
+ @key = data['key']
16
+ end
17
+
18
+ def repositories
19
+ @repositories ||= Repository.get_all(@bb,key)
20
+ end
21
+
22
+ def move_all_repos_to_project(new_project)
23
+ repositories.each do |r|
24
+ r.move_repo_to_project(new_project)
25
+ end
26
+ end
27
+
28
+ def set_hook_status(key,status,settings=nil)
29
+ repositories.each do |r|
30
+ r.set_hook_settings(key, settings) if status && settings
31
+ r.set_hook_status(key, status)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,66 @@
1
+ class Repository
2
+ include API
3
+ LIMIT=1000.to_s
4
+
5
+ def self.get_all(bb,project)
6
+ data = bb.request(:get, "rest/api/1.0/projects/#{project}/repos/?limit=#{LIMIT}")
7
+ data['values'].map {|p| new(bb,p) }
8
+ end
9
+
10
+ attr_reader :bb, :name, :project
11
+
12
+ def initialize(server,data)
13
+ @bb = server
14
+ @name = data['slug']
15
+ @project = data['project']['key']
16
+ end
17
+
18
+ def branch_permissions
19
+ bb.request(:get, "rest/branch-permissions/2.0/projects/#{project}/repos/#{name}/restrictions")['values']
20
+ end
21
+
22
+ def master_branch_protected?
23
+ !! branch_permissions.detect do |c|
24
+ c["type"] == 'fast-forward-only' && c["matcher"]["id"] == 'refs/heads/master'
25
+ end
26
+ end
27
+
28
+ def set_master_branch_protected
29
+ perm = {
30
+ "type"=>"fast-forward-only",
31
+ "matcher"=>
32
+ {"id"=>"refs/heads/master",
33
+ "displayId"=>"master",
34
+ "type"=>{"id"=>"BRANCH", "name"=>"Branch"},
35
+ "active"=>true},
36
+ "users"=>[],
37
+ "groups"=>[]
38
+ }.to_json
39
+ bb.request(:post, "rest/branch-permissions/2.0/projects/#{project}/repos/#{name}/restrictions", perm)
40
+ end
41
+
42
+ def move_repo_to_project(new_project)
43
+ bb.request(:post, "/rest/api/1.0/projects/#{project}/repos/#{name}",{project: {key: new_project}}.to_json)
44
+ bb.request(:delete, "/rest/api/1.0/projects/#{project}/repos/#{name}")
45
+ end
46
+
47
+ def hooks
48
+ bb.request(:get, "rest/api/1.0/projects/#{project}/repos/#{name}/settings/hooks")
49
+ end
50
+
51
+ def set_hook_status(key, status)
52
+ if status
53
+ bb.request(:put, "rest/api/1.0/projects/#{project}/repos/#{name}/settings/hooks/#{key}/enabled")
54
+ else
55
+ bb.request(:delete, "rest/api/1.0/projects/#{project}/repos/#{name}/settings/hooks/#{key}/enabled")
56
+ end
57
+ end
58
+
59
+ def hook_settings(key)
60
+ bb.request(:get, "rest/api/1.0/projects/#{project}/repos/#{name}/settings/hooks/#{key}/settings")
61
+ end
62
+
63
+ def set_hook_settings(key, settings)
64
+ bb.request(:put, "rest/api/1.0/projects/#{project}/repos/#{name}/settings/hooks/#{key}/settings", settings)
65
+ end
66
+ end
@@ -0,0 +1,40 @@
1
+ class ConfigStore
2
+ @@defaults_path = File.join(File.dirname(__FILE__),'../config/defaults.json')
3
+ @@overrides_path = File.expand_path('~/.config/api_deploy_overrides.json')
4
+
5
+ def self.defaults_path
6
+ @@defaults_path
7
+ end
8
+
9
+ def self.defaults_path=(path)
10
+ @@defaults_path = path
11
+ end
12
+
13
+ def self.overrides_path
14
+ @@overrides_path
15
+ end
16
+
17
+ def self.overrides_path=(path)
18
+ @@overrides_path = path
19
+ end
20
+
21
+ def self.load_config
22
+ warn "ConfigStoreuration overrides file not present at #{overrides_path}" unless File.exists?(overrides_path)
23
+ defaults = Hashie::Mash.new(JSON.parse(File.read(defaults_path))) if File.exists?(defaults_path)
24
+ overrides = JSON.parse(File.read(overrides_path)) if File.exists?(overrides_path)
25
+ defaults.deep_merge(overrides || {})
26
+ end
27
+
28
+ class << self
29
+ def teamcity; @@ConfigStore.teamcity; end
30
+ def artifactory; @@ConfigStore.artifactory; end
31
+ def octopus; @@ConfigStore.octopus; end
32
+ def bitbucket; @@ConfigStore.bitbucket; end
33
+ end
34
+
35
+ def self.set_config
36
+ @@ConfigStore = self.load_config
37
+ end
38
+
39
+ self.set_config
40
+ end
data/lib/github.rb ADDED
@@ -0,0 +1,13 @@
1
+ class GithubApi
2
+ attr_reader :api
3
+
4
+ ORG = 'YTech'
5
+
6
+
7
+ def initialize
8
+ @api = Github.new(
9
+ basic_auth: "#{ENV['GITHUB_API_USER']}:#{ENV['GITHUB_API_PASS']}",
10
+ org: ORG
11
+ )
12
+ end
13
+ end
data/lib/ldap.rb ADDED
@@ -0,0 +1,115 @@
1
+ class LdapApi
2
+
3
+ YOOX = {
4
+ name: 'YOOX',
5
+ host: 'ydcrootblq.yoox.net',
6
+ base: 'dc=yoox,dc=net',
7
+ port: 389,
8
+ user: ENV['YOOX_BIND_USER'],
9
+ pass: ENV['YOOX_BIND_PASS'],
10
+ }
11
+ NAP = {
12
+ name: 'LONDON',
13
+ host: 'RODC02-PR-IMO.london.net-a-porter.com',
14
+ base: 'dc=london,dc=net-a-porter,dc=com',
15
+ port: 389,
16
+ user: ENV['NAP_BIND_USER'],
17
+ pass: ENV['NAP_BIND_PASS'],
18
+ }
19
+
20
+ DOMAINS = [ YOOX, NAP ]
21
+
22
+ def domains
23
+ domain_structs = DOMAINS.map do |domain|
24
+ d = OpenStruct.new(
25
+ name: domain[:name],
26
+ user: domain[:user],
27
+ pass: domain[:pass],
28
+ ldap: Net::LDAP.new(
29
+ host: domain[:host],
30
+ port: domain[:port],
31
+ base: domain[:base],
32
+ auth: {
33
+ method: :simple,
34
+ username: domain[:user],
35
+ password: domain[:pass],
36
+ },
37
+ )
38
+ )
39
+ raise "BIND ERROR: #{domain}" unless d.ldap.bind
40
+ d
41
+ end
42
+ end
43
+
44
+ def auth?(username, password)
45
+ domains.each do |domain|
46
+ domain.ldap.authenticate domain.name + "\\" + username, password
47
+ return true if domain.ldap.bind
48
+ end
49
+ return false
50
+ end
51
+
52
+ def groups(name)
53
+ filter = Net::LDAP::Filter.eq("sAMAccountName", name)
54
+ results = []
55
+ domains.map do |domain|
56
+ domain.ldap.search(filter: filter) do |entry|
57
+ results << entry.memberof.map {|e| e.sub(/^CN=/,'').sub(/,.*$/,'') }
58
+ end
59
+ domain.ldap.get_operation_result
60
+ end
61
+ results.flatten
62
+ end
63
+
64
+ def user(name)
65
+ filter = Net::LDAP::Filter.eq("sAMAccountName", name)
66
+ results = []
67
+ domains.map do |domain|
68
+ domain.ldap.search(filter: filter) do |entry|
69
+ results << entry
70
+ end
71
+ domain.ldap.get_operation_result
72
+ end
73
+ results.flatten
74
+ end
75
+
76
+ def group(name)
77
+ filter = Net::LDAP::Filter.eq("cn", name)
78
+ results = []
79
+ domains.map do |domain|
80
+ domain.ldap.search(filter: filter) do |entry|
81
+ results << entry
82
+ end
83
+ domain.ldap.get_operation_result
84
+ end
85
+ results.flatten
86
+ end
87
+
88
+ def in_group?(name, group)
89
+ groups(name).include?(group)
90
+ end
91
+
92
+ def users_in_group(group)
93
+ filter = Net::LDAP::Filter.eq("cn", group)
94
+ results = []
95
+ domains.map do |domain|
96
+ domain.ldap.search(filter: filter) do |entry|
97
+ results << entry.member.map {|e| user_from_name(e.sub(/^CN=/,'').sub(/,.*$/,'')) }
98
+ end
99
+ domain.ldap.get_operation_result
100
+ end
101
+ results.flatten
102
+ end
103
+
104
+ def user_from_name(name)
105
+ filter = Net::LDAP::Filter.eq("cn", name)
106
+ results = []
107
+ domains.map do |domain|
108
+ domain.ldap.search(filter: filter) do |entry|
109
+ results << entry[:samaccountname]
110
+ end
111
+ domain.ldap.get_operation_result
112
+ end
113
+ results.flatten
114
+ end
115
+ end
data/lib/libraries.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'artifactory'
2
+ require 'faraday'
3
+ require 'json'
4
+ require 'hashie'
5
+ require 'logging'
6
+ require 'require_all'
7
+ require 'net/ldap'
8
+ require 'github_api'
9
+
10
+ require_rel '../lib'
data/lib/log.rb ADDED
@@ -0,0 +1,13 @@
1
+ class Log
2
+ class << self
3
+ def logger
4
+ @logger ||= ::Logging.logger(STDOUT)
5
+ @logger.level = ENV.fetch("LOG_LEVEL", "warn").to_sym
6
+ @logger
7
+ end
8
+ def warn(m); logger.warn(m); end
9
+ def info(m); logger.info(m); end
10
+ def debug(m); logger.debug(m); end
11
+ def level=(l); logger.level = l; end
12
+ end
13
+ end
@@ -0,0 +1,56 @@
1
+ class OctopusApi
2
+ include API
3
+
4
+ RESOURCE_TYPES = ['Environments','Projects','ProjectGroups','NugetFeeds','LibraryVariableSets','Machines','Lifecycles','Users','Releases','Deployments']
5
+
6
+
7
+ def initialize
8
+ create_api(ConfigStore.octopus)
9
+ end
10
+
11
+ def create_resource(type, query)
12
+ check_type type
13
+ request(:post, "/#{type}", query)
14
+ end
15
+
16
+ def remove_resource(type, id)
17
+ check_type type
18
+ request(:delete, "/#{type}/#{id}")
19
+ end
20
+
21
+ def get_resource(type)
22
+ check_type type
23
+ return request(:get, "/#{type}/all")
24
+ end
25
+
26
+ def resource_exists?(type, name)
27
+ resource = get_resource_by_type_and_name(type, name)
28
+ return (resource && resource != [])
29
+ end
30
+
31
+ def get_resource_by_type_and_name(type, name = nil)
32
+ resources = get_resource(type)
33
+ if name && name != ''
34
+ filter = [*name].join("|")
35
+
36
+ filtered_resources = resources.select do |resource|
37
+ resource['Name'] =~ /#{filter}/
38
+ end
39
+
40
+ if filtered_resources.any?
41
+ Log.info "#{filtered_resources.count} resources found with filter #{filter}"
42
+ filtered_resources
43
+ else
44
+ Log.info "No #{type} found with filter #{filter}"
45
+ return nil
46
+ end
47
+ else
48
+ resources
49
+ end
50
+ end
51
+
52
+ def check_type(type)
53
+ raise NameError, "Invalid resource type supplied: '#{type}'" unless RESOURCE_TYPES.include? type
54
+ end
55
+ end
56
+
@@ -0,0 +1,40 @@
1
+ class TeamcityApi
2
+ include API
3
+
4
+ def initialize
5
+ create_api( ConfigStore.teamcity )
6
+ end
7
+
8
+ def build_queue
9
+ request(:get, 'buildQueue')
10
+ end
11
+
12
+ def create_build(build_config_id, properties={})
13
+ properties_string = ""
14
+ properties.each_pair do |k,v|
15
+ properties_string << "<property name='#{k}' value='#{v}'/>\n"
16
+ end
17
+ data = "
18
+ <build>
19
+ <buildType id='#{build_config_id}'/>
20
+ <properties>
21
+ #{properties_string}
22
+ </properties>
23
+ </build>
24
+ "
25
+ request(:post, 'buildQueue', data, "xml")
26
+ end
27
+
28
+ def set_project_parameter(project_id,parameter,value)
29
+ request(:put, "projects/#{project_id}/parameters/#{parameter}", value, "text")
30
+ end
31
+
32
+ def projects(parent_id=nil)
33
+ list = Nokogiri::XML.parse(request(:get, 'projects').body)
34
+ if parent_id
35
+ (list.xpath '//project').select {|e| e.attributes['parentProjectId'].to_s == parent_id}
36
+ else
37
+ list
38
+ end
39
+ end
40
+ end