lib/pdksync.rb in pdksync-0.2.0 vs lib/pdksync.rb in pdksync-0.3.0

- old
+ new

@@ -7,10 +7,11 @@ require 'octokit' require 'pdksync/constants' require 'json' require 'yaml' require 'colorize' +require 'bundler' # @summary # This module set's out and controls the pdksync process # @param [String] @access_token # The token used to access github, must be exported locally. @@ -30,16 +31,20 @@ @namespace = Constants::NAMESPACE @pdksync_dir = Constants::PDKSYNC_DIR @push_file_destination = Constants::PUSH_FILE_DESTINATION @create_pr_against = Constants::CREATE_PR_AGAINST @managed_modules = Constants::MANAGED_MODULES + @default_pdksync_label = Constants::PDKSYNC_LABEL def self.main(steps: [:clone], args: nil) create_filespace client = setup_client module_names = return_modules + raise "No modules found in '#{@managed_modules}'" if module_names.nil? + validate_modules_exist(module_names) pr_list = [] + # The current directory is saved for cleanup purposes main_path = Dir.pwd # validation run_a_command if steps.include?(:run_a_command) @@ -99,13 +104,15 @@ if steps.include?(:pdk_update) Dir.chdir(main_path) unless Dir.pwd == main_path next unless pdk_update(output_path).zero? if steps.include?(:use_pdk_ref) ref = return_template_ref + pr_title = args[:additional_title] ? "#{args[:additional_title]} - pdksync_#{ref}" : "pdksync_#{ref}" args = { branch_name: "pdksync_#{ref}", commit_message: "pdksync_#{ref}", - pr_title: "pdksync_#{ref}" } + pr_title: pr_title, + pdksync_label: @default_pdksync_label } end print 'pdk update, ' end if steps.include?(:create_commit) Dir.chdir(main_path) unless Dir.pwd == main_path @@ -117,13 +124,34 @@ Dir.chdir(main_path) unless Dir.pwd == main_path git_instance = Git.open(output_path) push_staged_files(git_instance, git_instance.current_branch, repo_name) print 'push, ' pdk_version = return_pdk_version("#{output_path}/metadata.json") + + # If a label is supplied, verify that it is available in the repo + label = args[:pdksync_label] ? args[:pdksync_label] : args[:label] + label_valid = (label.is_a?(String) && !label.to_str.empty?) ? check_for_label(client, repo_name, label) : nil + + # Exit current iteration if an error occured retrieving a label + if label_valid == false + raise 'Ensure label is valid' + end + + # Create the PR and add link to pr list pr = create_pr(client, repo_name, git_instance.current_branch, pdk_version, args[:pr_title]) + if pr.nil? + break + end + pr_list.push(pr.html_url) print 'created pr, ' + + # If a valid label is supplied, add this to the PR + if label_valid == true + add_label(client, repo_name, pr.number, label) + print "added label '#{label}' " + end end if steps.include?(:clean_branches) Dir.chdir(main_path) unless Dir.pwd == main_path delete_branch(client, repo_name, args[:branch_name]) print 'branch deleted, ' @@ -158,14 +186,32 @@ # @summary # This method when called will access a file set by the global variable '@managed_modules' and retrieve the information within as an array. # @return [Array] # An array of different module names. def self.return_modules + raise "File '#{@managed_modules}' is empty/does not exist" if File.size?(@managed_modules).nil? YAML.safe_load(File.open(@managed_modules)) end # @summary + # This method when called will parse an array of module names and verify whether they are valid GitHub repo names + # @param [Array] module_names + # String array of the names of GitHub repos + def self.validate_modules_exist(module_names) + invalid_names = [] + module_names.each do |module_name| + # If module name is invalid, push it to invalid names array + unless Octokit.repository?("#{@namespace}/#{module_name}") + invalid_names.push(module_name) + next + end + end + # Raise error if any invalid matches were found + raise "Could not find the following repositories: #{invalid_names}" unless invalid_names.empty? + end + + # @summary # Try to use a fully installed pdk, otherwise fall back to the bundled pdk gem. # @return String # Path to the pdk executable def self.return_pdk_path full_path = '/opt/puppetlabs/pdk/bin/pdk' @@ -216,12 +262,25 @@ # @param [String] command # The command to be run. # @return [Integer] # The status code of the command run. def self.run_command(output_path, command) + stdout = '' + stderr = '' + status = Process::Status + Dir.chdir(output_path) unless Dir.pwd == output_path - stdout, stderr, status = Open3.capture3(command) + + # Environment cleanup required due to Ruby subshells using current Bundler environment + if command =~ %r{^bundle} + Bundler.with_clean_env do + stdout, stderr, status = Open3.capture3(command) + end + else + stdout, stderr, status = Open3.capture3(command) + end + puts "\n#{stdout}\n".yellow puts "(FAILURE) Unable to run command '#{command}': #{stderr}".red unless status.exitstatus.zero? status.exitstatus end @@ -342,9 +401,56 @@ title, message) pr rescue StandardError => error puts "(FAILURE) PR creation for #{repo_name} has failed. #{error}".red + end + + # @summary + # This method when called will check on the given repository for the existence of the supplied label + # @param [Octokit::Client] client + # The octokit client used to gain access to and manipulate the repository. + # @param [String] repo_name + # The name of the repository on which the commit is to be made. + # @param [String] label + # The label to check for. + # @return [Boolean] + # A boolean stating whether the label was found. + def self.check_for_label(client, repo_name, label) + # Get labels from repository + repo_labels = client.labels(repo_name) + + # Look for label in the repository's labels + match = false + repo_labels.each do |repo_label| + if repo_label.name == label + match = true + break + end + end + + # Raise error if a match was not found else return true + (match == false) ? (raise StandardError, "Label '#{label}' not found in #{repo_name}") : (return true) + rescue StandardError => error + puts "(FAILURE) Retrieving labels for #{repo_name} has failed. #{error}".red + return false + end + + # @summary + # This method when called will add a given label to a given repository + # @param [Octokit::Client] client + # The octokit client used to gain access to and manipulate the repository. + # @param [String] repo_name + # The name of the repository on which the commit is to be made. + # @param [Integer] issue_number + # The id of the issue (i.e. pull request) to add the label to. + # @param [String] label + # The label to add. + def self.add_label(client, repo_name, issue_number, label) + client.update_issue(repo_name, issue_number, labels: [label]) + rescue StandardError => error + puts "(FAILURE) Adding label to #{repo_name} issue #{issue_number} has failed. #{error}".red + return false end # @summary # This method when called will delete any preexisting branch on the given repository that matches the given name. # @param [Octokit::Client] client