Class: Dependabot::Linguist::DependabotFileValidator
- Inherits:
-
Object
- Object
- Dependabot::Linguist::DependabotFileValidator
- Defined in:
- lib/dependabot/linguist/dependabot_file_validator.rb
Overview
Reads an existing dependabot file and determines how it should be updated to meet the suggested entried to the updates list coming from repository’s directories_per_ecosystem_validated_by_dependabot
Defined Under Namespace
Modules: ConfigDriftStatus
Constant Summary collapse
- YAML_FILE_PATH =
".github/dependabot.yaml"
- YML_FILE_PATH =
".github/dependabot.yml"
- CONFIG_FILE_PATH =
".github/.dependabot-linguist"
Class Method Summary collapse
- .checking_exists(checking, exists) ⇒ Object
- .flatten_ecodirs_to_ecodir(ecosystem_directories_map) ⇒ Object
Instance Method Summary collapse
-
#commit_new_config ⇒ Object
The expected environment to run this final step in should have ‘git’ AND ‘gh’ available as commands to run, and calls out to a subshell to run them as set up by the environment that runs this, rather than requiring credentials being provided to this class.
- #config_drift ⇒ Object
- #confirm_config_version_is_valid ⇒ Object
-
#dependabot_file_path ⇒ Object
rubocop:disable Layout/IndentationWidth, Layout/ElseAlignment, Layout/EndAlignment.
-
#ecodir_is_ignored(eco, dir) ⇒ Object
Is a yaml config file exists that looks like.
- #existing_config ⇒ Object
-
#initialize(repo_path, remove_undiscovered: false, update_existing: true, minimum_interval: "weekly", max_open_pull_requests_limit: 5, verbose: false) ⇒ DependabotFileValidator
constructor
A new instance of DependabotFileValidator.
-
#load_ecosystem_directories(incoming: @load_ecosystem_directories) ⇒ Object
Expects an input that is the output of ::Dependabot::Linguist::Repository.new(~)‘s directories_per_ecosystem_validated_by_dependabot, which should be a map => [“<folder_path>”, …], ….
- #meta_config ⇒ Object
- #new_config ⇒ Object
- #parsed_schedule_interval(interval) ⇒ Object
- #write_new_config ⇒ Object
Constructor Details
#initialize(repo_path, remove_undiscovered: false, update_existing: true, minimum_interval: "weekly", max_open_pull_requests_limit: 5, verbose: false) ⇒ DependabotFileValidator
Returns a new instance of DependabotFileValidator.
12 13 14 15 16 17 18 19 20 |
# File 'lib/dependabot/linguist/dependabot_file_validator.rb', line 12 def initialize(repo_path, remove_undiscovered: false, update_existing: true, minimum_interval: "weekly", max_open_pull_requests_limit: 5, verbose: false) @repo = Rugged::Repository.new(repo_path) @remove_undiscovered = remove_undiscovered @update_existing = update_existing @minimum_interval = minimum_interval @max_open_pull_requests_limit = [max_open_pull_requests_limit, 0].max @verbose = verbose @load_ecosystem_directories ||= nil end |
Class Method Details
.checking_exists(checking, exists) ⇒ Object
98 99 100 |
# File 'lib/dependabot/linguist/dependabot_file_validator.rb', line 98 def self.checking_exists(checking, exists) exists["package-ecosystem"] == checking[0] && exists["directory"] == checking[1] end |
.flatten_ecodirs_to_ecodir(ecosystem_directories_map) ⇒ Object
94 95 96 |
# File 'lib/dependabot/linguist/dependabot_file_validator.rb', line 94 def self.flatten_ecodirs_to_ecodir(ecosystem_directories_map) ecosystem_directories_map.collect { |eco, dirs| dirs.collect { |dir| [eco, dir] } }.flatten(1) end |
Instance Method Details
#commit_new_config ⇒ Object
The expected environment to run this final step in should have ‘git’ AND ‘gh’ available as commands to run, and calls out to a subshell to run them as set up by the environment that runs this, rather than requiring credentials being provided to this class.
214 215 216 217 218 219 220 221 222 223 |
# File 'lib/dependabot/linguist/dependabot_file_validator.rb', line 214 def commit_new_config new_branch = @repo.create_branch("dependabot-linguist_auto-config-update") in_repo = "cd #{@repo.path.delete_suffix("/.git/")} &&" `#{"#{in_repo} git checkout #{new_branch.name}"}` write_new_config `#{"#{in_repo} git add #{dependabot_file_path}"}` `#{"#{in_repo} git commit -m \"Auto update #{dependabot_file_path} -- dependabot-linguist\""}` `#{"#{in_repo} git push --set-upstream #{@repo.remotes["origin"].name} #{new_branch.name}"}` `#{"#{in_repo} gh pr create --fill"}` end |
#config_drift ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/dependabot/linguist/dependabot_file_validator.rb', line 108 def config_drift confirm_config_version_is_valid @config_drift ||= {}.tap do |this| ecodir_list = self.class.flatten_ecodirs_to_ecodir(load_ecosystem_directories) this[ConfigDriftStatus::ALREADY_IN] = [] this[ConfigDriftStatus::TO_BE_ADDED] = [] this[ConfigDriftStatus::UNDISCOVERED] = [] this.freeze ecodir_list.each do |checking_ecodir| next if ecodir_is_ignored(checking_ecodir[0], checking_ecodir[1]) if !existing_config.empty? && !existing_config["updates"].nil? existed_ecodir = nil existing_config["updates"].each do |existing_ecodir| if self.class.checking_exists(checking_ecodir, existing_ecodir) puts "#{ConfigDriftStatus::ALREADY_IN}; {#{checking_ecodir[0]} @ #{checking_ecodir[1]}}" if @verbose this[ConfigDriftStatus::ALREADY_IN].append(checking_ecodir) existed_ecodir = existing_ecodir break # existing_ecodir end end # break to here next unless existed_ecodir.nil? # checking_ecodir end # If we didn't break -> next, then we've got a checking_ecodir # that we didn't find already present in the existing ecodirs. puts "#{ConfigDriftStatus::TO_BE_ADDED}; {#{checking_ecodir[0]} @ #{checking_ecodir[1]}}" if @verbose this[ConfigDriftStatus::TO_BE_ADDED].append(checking_ecodir) end if !existing_config.empty? && !existing_config["updates"].nil? existing_config["updates"].each do |existing_ecodir| existed_ecodir = nil ecodir_list.each do |checking_ecodir| break if ecodir_is_ignored(checking_ecodir[0], checking_ecodir[1]) existed_ecodir = checking_ecodir if self.class.checking_exists(checking_ecodir, existing_ecodir) break unless existed_ecodir.nil? end if existed_ecodir.nil? puts "#{ConfigDriftStatus::UNDISCOVERED}; {#{existing_ecodir["package-ecosystem"]} @ #{existing_ecodir["directory"]}} that wasn't found by us!!" if @verbose this[ConfigDriftStatus::UNDISCOVERED].append([existing_ecodir["package-ecosystem"], existing_ecodir["directory"]]) end end end end end |
#confirm_config_version_is_valid ⇒ Object
76 77 78 |
# File 'lib/dependabot/linguist/dependabot_file_validator.rb', line 76 def confirm_config_version_is_valid raise StandardError("The existing config has a version other than 2") unless existing_config["version"] == 2 end |
#dependabot_file_path ⇒ Object
rubocop:disable Layout/IndentationWidth, Layout/ElseAlignment, Layout/EndAlignment
30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/dependabot/linguist/dependabot_file_validator.rb', line 30 def dependabot_file_path @dependabot_file_path ||= if @repo.blob_at(@repo.head.target_id, YML_FILE_PATH) # the yml extension is preferred by GitHub, so even though this # returns the same as the `else`, check it before YAML. YML_FILE_PATH elsif @repo.blob_at(@repo.head.target_id, YAML_FILE_PATH) YAML_FILE_PATH else @existing_config = { "version" => 2, "updates" => [] } YML_FILE_PATH end end |
#ecodir_is_ignored(eco, dir) ⇒ Object
Is a yaml config file exists that looks like
ignore:
directory:
/path/to/somewhere:
- some_ecosystem
ecosystem:
some_other_ecosystem:
- /path/to/somewhere_else
then both (some_ecosystem, “/path/to/somewhere”) and (some_other_ecosystem, “/path/to/somewhere_else”) should be “ignored” by this system.
72 73 74 |
# File 'lib/dependabot/linguist/dependabot_file_validator.rb', line 72 def ecodir_is_ignored(eco, dir) ((((["ignore"] || {})["directory"] || {})[dir] || []).any? eco) || ((((["ignore"] || {})["ecosystem"] || {})[eco] || []).any? dir) end |
#existing_config ⇒ Object
43 44 45 46 47 |
# File 'lib/dependabot/linguist/dependabot_file_validator.rb', line 43 def existing_config dependabot_file_path # to = {} if the file doesn't exist or isn't committed. # @existing_config ||= YAML.load_file(File.join(@repo.path, dependabot_file_path)) @existing_config ||= YAML.safe_load(@repo.blob_at(@repo.head.target_id, dependabot_file_path).content) end |
#load_ecosystem_directories(incoming: @load_ecosystem_directories) ⇒ Object
Expects an input that is the output of ::Dependabot::Linguist::Repository.new(~)‘s directories_per_ecosystem_validated_by_dependabot, which should be a map => [“<folder_path>”, …], …
83 84 85 86 87 88 89 90 91 92 |
# File 'lib/dependabot/linguist/dependabot_file_validator.rb', line 83 def load_ecosystem_directories(incoming: @load_ecosystem_directories) @load_ecosystem_directories ||= nil if @load_ecosystem_directories == incoming @load_ecosystem_directories else @config_drift = nil @new_config = nil @load_ecosystem_directories = incoming end end |
#meta_config ⇒ Object
49 50 51 52 53 54 55 |
# File 'lib/dependabot/linguist/dependabot_file_validator.rb', line 49 def @meta_config ||= if @repo.blob_at(@repo.head.target_id, CONFIG_FILE_PATH) YAML.safe_load(@repo.blob_at(@repo.head.target_id, CONFIG_FILE_PATH).content) else {} end end |
#new_config ⇒ Object
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/dependabot/linguist/dependabot_file_validator.rb', line 162 def new_config confirm_config_version_is_valid @new_config ||= YAML.safe_load(existing_config.to_yaml).tap do |this| this["updates"] = [] if this["updates"].nil? # If "remove_undiscovered" is set, then set this to reject any # updates that are in the list of those undiscovered. Removing # is not safe from inside each, so reject instead. this["updates"] = this["updates"].reject { |u| config_drift[ConfigDriftStatus::UNDISCOVERED].any? [u["package-ecosystem"], u["directory"]] } if @remove_undiscovered # Next, go through and update any existing. if @update_existing this["updates"].each do |existing_update| if config_drift[ConfigDriftStatus::ALREADY_IN].any? [existing_update["package-ecosystem"], existing_update["directory"]] # Confirm that the already present entry is good enough if existing_update["schedule"].is_a? Hash new_interval = parsed_schedule_interval(existing_update["schedule"]["interval"]) existing_update["schedule"]["interval"] = new_interval # if it's not weekly anymore remove day if it's specified. if existing_update["schedule"]["interval"] != "weekly" existing_update["schedule"].delete("day") end else existing_update["schedule"] = { "interval" => parsed_schedule_interval("monthly") } end # Confirm the open-pull-requests-limit if existing_update["open-pull-requests-limit"] existing_update["open-pull-requests-limit"] = [existing_update["open-pull-requests-limit"], @max_open_pull_requests_limit].min else existing_update["open-pull-requests-limit"] = @max_open_pull_requests_limit end existing_update.delete("open-pull-requests-limit") if existing_update["open-pull-requests-limit"] == 5 end end end config_drift[ConfigDriftStatus::TO_BE_ADDED].each do |tba| new_update = { "package-ecosystem" => tba[0], "directory" => tba[1] } new_update["schedule"] = { "interval" => parsed_schedule_interval("monthly") } new_update["open-pull-requests-limit"] = @max_open_pull_requests_limit if @max_open_pull_requests_limit != 5 this["updates"].append(new_update) end end end |
#parsed_schedule_interval(interval) ⇒ Object
153 154 155 156 157 158 159 160 |
# File 'lib/dependabot/linguist/dependabot_file_validator.rb', line 153 def parsed_schedule_interval(interval) intervals = ["daily", "weekly", "monthly"].freeze if intervals.any? @minimum_interval intervals[[intervals.find_index(@minimum_interval) || (intervals.length-1), intervals.find_index(interval) || (intervals.length-1)].min] else interval end end |
#write_new_config ⇒ Object
204 205 206 207 208 |
# File 'lib/dependabot/linguist/dependabot_file_validator.rb', line 204 def write_new_config full_file_path = "#{@repo.path.delete_suffix("/.git/")}/#{dependabot_file_path}" FileUtils.mkdir_p File.dirname(full_file_path) File.open(full_file_path, "w") { |file| file.write(new_config.to_yaml) } if new_config != existing_config end |