Class: Sandbox

Inherits:
Object
  • Object
show all
Includes:
ReleaseManager::Git::Utilities, ReleaseManager::Logger, ReleaseManager::VCSManager
Defined in:
lib/release_manager/sandbox.rb

Instance Attribute Summary collapse

Attributes included from ReleaseManager::VCSManager

#vcs

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ReleaseManager::Git::Utilities

#add_all, #add_file, #add_remote, #apply_diff, #apply_patch, #author, #author_email, #author_name, #branch_exist?, #changed_files, #checkout_branch, #cherry_pick, #cli_create_commit, #clone, #create_branch, #create_commit, #create_diff, #create_diff_obj, #create_local_tag, #credentials, #current_branch, #current_branch?, #delete_branch, #fetch, #find_or_create_remote, #find_ref, #get_content, #git_command, #git_url?, #push_branch, #push_tags, #rebase_branch, #remote_exists?, #remote_from_name, #remote_from_url, #remote_url_matches?, #remove_file, #repo, #transports, #up2date?, #update_cli_index

Methods included from ReleaseManager::Logger

#color, #log_level, #logger

Methods included from ReleaseManager::VCSManager

adapter_instance, adapter_types, default_instance

Constructor Details

#initialize(name, modules, control_repo_path, repos_dir = nil, options = {}) ⇒ Sandbox

Returns a new instance of Sandbox.



18
19
20
21
22
23
24
# File 'lib/release_manager/sandbox.rb', line 18

def initialize(name, modules, control_repo_path, repos_dir = nil, options = {})
  @name = name
  @repos_dir = repos_dir
  @module_names = modules
  @control_repo_path = control_repo_path
  @options = options
end

Instance Attribute Details

#control_repoControlRepo (readonly)

Returns - a ControlRepo object.

Returns:



45
46
47
# File 'lib/release_manager/sandbox.rb', line 45

def control_repo
  @control_repo
end

#control_repo_pathString (readonly)

Returns the r10k control repo path, defaults to ~/repos/r10k-control.

Returns:

  • (String)

    the r10k control repo path, defaults to ~/repos/r10k-control



40
41
42
# File 'lib/release_manager/sandbox.rb', line 40

def control_repo_path
  @control_repo_path
end

#module_namesObject (readonly)

Returns the value of attribute module_names.



11
12
13
# File 'lib/release_manager/sandbox.rb', line 11

def module_names
  @module_names
end

#modulesObject (readonly)



185
186
187
# File 'lib/release_manager/sandbox.rb', line 185

def modules
  @modules
end

#nameObject (readonly)

Returns the value of attribute name.



11
12
13
# File 'lib/release_manager/sandbox.rb', line 11

def name
  @name
end

#optionsObject (readonly)

Returns the value of attribute options.



11
12
13
# File 'lib/release_manager/sandbox.rb', line 11

def options
  @options
end

#repos_dirString (readonly)

Returns the repos_path, defaults to ~/repos.

Returns:

  • (String)

    the repos_path, defaults to ~/repos



35
36
37
# File 'lib/release_manager/sandbox.rb', line 35

def repos_dir
  @repos_dir
end

Class Method Details

.create(name, options) ⇒ Object

the user passes in the r10k git url or path or we assume the path if the user does not pass in the git url we assume the repo already exist if the repo doesn’t exist we clone the url

Parameters:

  • name (String)
    • the name of the sandbox

  • Array[String] (Array[String] modules - the names of the modules that should be forked and branched)

    modules - the names of the modules that should be forked and branched

  • repos_dir (String)
    • the path to the repos directory

  • control_repo_path (String)
    • the url or path to the r10k control repo

  • [String] (Hash)

    a customizable set of options



211
212
213
214
215
216
217
218
# File 'lib/release_manager/sandbox.rb', line 211

def self.create(name, options)
  box = Sandbox.new(name, options[:modules],
                    options[:r10k_repo_path],
                    options[:repos_path], options)
  box.check_requirements
  box.verify_api_token
  box.create(options[:r10k_repo_url])
end

Instance Method Details

#check_requirementsObject



193
194
195
196
197
198
199
200
# File 'lib/release_manager/sandbox.rb', line 193

def check_requirements
  begin
    add_ssh_key
  rescue InvalidModuleNameException => e
    logger.error(e.message)
    exit 1
  end
end

#create(r10k_url) ⇒ Object

checkout and/or create branch get modules fork module unless already exists clone fork of module create branch of fork set module fork set module branch set upstream to original namespace cleanup branches



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/release_manager/sandbox.rb', line 137

def create(r10k_url)
  setup_repos_dir(repos_dir)
  @control_repo = setup_control_repo(r10k_url)
  # get modules we are interested in
  module_names.each do | mod_name |
    puts "## #{mod_name} ##".yellow
    begin
      mod = puppetfile.find_mod(mod_name)
      setup_module_repo(mod)
    rescue Rugged::CheckoutError => e
      logger.fatal(e.message)
      exit 1
    rescue InvalidModuleNameException => e
      logger.error(e.message)
      value = nil
      loop do
        print "Do you want to create a new entry in the Puppetfile for the module named #{mod_name}?(y/n): ".yellow
        value = gets.downcase.chomp
        break if value =~ /y|n/
      end
      next if value == 'n'
      mod = setup_new_module(mod_name)
      setup_module_repo(mod)
    end
  end
  @control_repo.checkout_branch(name)
  puppetfile.write_to_file
  logger.info("Committing Puppetfile changes to r10k-control branch: #{name}")
  committed = puppetfile.commit("Sandbox Creation for #{name} environment")
  # no need to push if we didn't commit anything
  if committed
    logger.info("Pushing new environment branch: #{name} to upstream")
    puppetfile.push('upstream', name, true)
  end
  logger.info("Sandbox created successfully")
  return self
end

#puppetfileObject



189
190
191
# File 'lib/release_manager/sandbox.rb', line 189

def puppetfile 
  @puppetfile ||= control_repo.puppetfile
end

#setup_control_repo(url) ⇒ ControlRepo

Returns - creates a new control repo object and clones the url unless already cloned.

Parameters:

  • url (String)
    • the url to clone and fork

Returns:

  • (ControlRepo)
    • creates a new control repo object and clones the url unless already cloned



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/release_manager/sandbox.rb', line 51

def setup_control_repo(url)
  # clone r10k unless already cloned
  puts "## r10k-control ##".yellow
  fork = create_repo_fork(url)
  c = ControlRepo.create(control_repo_path, fork.ssh_url_to_repo)
  c.add_remote(fork.ssh_url_to_repo, 'myfork')
  c.fetch('myfork')
  c.fetch('origin')
  c.add_remote(url, 'upstream')
  # if the user doesn't have the branch, we create from upstream
  # and then checkout from the fork, we defer pushing the branch to later after updating the puppetfile
  target = c.branch_exist?("upstream/#{name}") ? "upstream/#{name}" : 'upstream/dev'
  # if the user has previously created the branch but doesn't exist locally, no need to create
  c.create_branch(name, target)
  c.checkout_branch(name)
  c
end

#setup_module_repo(mod) ⇒ PuppetModule

if the fork is already created, do nothing

Parameters:

  • mod (ControlMod)
    • the module to clone and fork

  • create_fork (Boolean)
    • defaults to true which creates a fork

Returns:

  • (PuppetModule)
    • creates a new puppet_module object and clones the url unless already cloned

Raises:



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/release_manager/sandbox.rb', line 73

def setup_module_repo(mod)
  raise InvalidModule.new(mod) unless mod.instance_of?(ControlMod)
  fork = create_repo_fork(mod.repo)
  m = PuppetModule.create(File.join(repos_dir, mod.name), fork.ssh_url_to_repo, name)
  m.fetch('origin')
  m.add_remote(fork.ssh_url_to_repo, 'myfork')
  # without the following, we risk accidently setting the upstream to the newly forked url
  # this occurs because r10k-control branch contains the forked url instead of the upstream url
  # we assume the metadata.source attribute contains the correct upstream url
  begin
    delay_source_change = false
    if m.source =~ /\Agit\@/
      m.add_remote(m.source, 'upstream', true)
    else
      logger.warn("Module's source is not defined correctly for #{m.name} should be a git url, fixing...")
      # delay the changing of metadata source until we checkout the branch
      delay_source_change = true
      m.add_remote(mod.repo, 'upstream', true)
    end
  rescue ModNotFoundException => e
    logger.error("Is #{mod.name} a puppet module?  Can't find the metadata source")
  end
  # if the user doesn't have the branch, we create from upstream
  # and then checkout from the fork
  # if the user has previously created the branch but doesn't exist locally, no need to create
  if m.remote_exists?('upstream')
    target = m.branch_exist?("myfork/#{name}") ? "myfork/#{name}" : 'upstream/master'
  else
    # don't create from upstream since the upstream remote does not exist
    # upstream does not exist because the url in the metadata source is not a git url
    target = 'master'
  end
  m.create_branch(name, target)
  m.push_branch('myfork', name)
  m.checkout_branch(name)
  if delay_source_change
    m.source = mod.repo
    m.
  end
  logger.info("Updating r10k-control Puppetfile to use fork: #{fork.ssh_url_to_repo} with branch: #{name}")
  puppetfile.write_source(mod.name, fork.ssh_url_to_repo, name )
  m
end

#setup_new_module(mod_name) ⇒ Object



117
118
119
120
121
122
123
124
125
126
# File 'lib/release_manager/sandbox.rb', line 117

def setup_new_module(mod_name)
  repo_url = nil
  loop do
    print "Please enter the git url of the source repo : ".yellow
    repo_url = gets.chomp
    break if repo_url =~ /git\@/
    puts "Repo Url must be a git url".red
  end
  puppetfile.add_module(mod_name, git: repo_url)
end

#setup_repos_dir(repos_path) ⇒ String

Creates the repos path using mkdir_p unless the path already exists

Parameters:

  • repos_path (String)
    • the path to the repos directory where you want to clone modules

Returns:



29
30
31
32
# File 'lib/release_manager/sandbox.rb', line 29

def setup_repos_dir(repos_path)
  FileUtils.mkdir_p(repos_path) unless File.exists?(repos_path)
  repos_path
end

#verify_api_tokenObject

TODO: extract this out to an adapter



176
177
178
179
180
181
182
# File 'lib/release_manager/sandbox.rb', line 176

def verify_api_token
  begin
    Gitlab.user
  rescue Exception => e
    raise InvalidToken.new(e.message)
  end
end