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, #fetch_cli, #find_or_create_remote, #find_ref, #find_tag, #get_content, #git_command, #git_url?, #push_branch, #push_tags, #rebase_branch, #ref_exists?, #remote_exists?, #remote_from_name, #remote_from_url, #remote_url_matches?, #remove_file, #repo, #tag_exists?, #tags, #transports, #up2date?

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)



194
195
196
# File 'lib/release_manager/sandbox.rb', line 194

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



220
221
222
223
224
225
226
227
228
# File 'lib/release_manager/sandbox.rb', line 220

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



202
203
204
205
206
207
208
209
# File 'lib/release_manager/sandbox.rb', line 202

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



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
174
175
176
177
178
179
180
181
182
# File 'lib/release_manager/sandbox.rb', line 140

def create(r10k_url)
  begin
    setup_repos_dir(repos_dir)
    @control_repo = setup_control_repo(r10k_url, options[:src_target])
  # get modules we are interested in
  rescue InvalidBranchName => e
    logger.error(e.message)
    exit 1
  end

  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, false)
  end
  logger.info("Sandbox created successfully")
  return self
end

#puppetfileObject



198
199
200
# File 'lib/release_manager/sandbox.rb', line 198

def puppetfile 
  @puppetfile ||= control_repo.puppetfile
end

#setup_control_repo(url, src_target = 'upstream/dev') ⇒ ControlRepo

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

Parameters:

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

  • src_target (String) (defaults to: 'upstream/dev')
    • the source to checkout from, defaults to ‘upstream/dev’

Returns:

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

Raises:



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

def setup_control_repo(url, src_target = 'upstream/dev')
  src_target ||= 'upstream/dev'
  # 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')
  raise InvalidBranchName.new("The source #{src_target} does not exist") unless c.branch_exist?(src_target)
  # 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}" : src_target
  # 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:



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
116
117
118
# File 'lib/release_manager/sandbox.rb', line 76

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



120
121
122
123
124
125
126
127
128
129
# File 'lib/release_manager/sandbox.rb', line 120

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



185
186
187
188
189
190
191
# File 'lib/release_manager/sandbox.rb', line 185

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