Class: Dependabot::Linguist::DependabotFileValidator
- Inherits:
-
Object
- Object
- Dependabot::Linguist::DependabotFileValidator
show all
- 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
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
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
end
end
next unless existed_ecodir.nil?
end
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)
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)
((((meta_config["ignore"] || {})["directory"] || {})[dir] || []).any? eco) || ((((meta_config["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
@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
|
49
50
51
52
53
54
55
|
# File 'lib/dependabot/linguist/dependabot_file_validator.rb', line 49
def meta_config
@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?
this["updates"] = this["updates"].reject { |u| config_drift[ConfigDriftStatus::UNDISCOVERED].any? [u["package-ecosystem"], u["directory"]] } if @remove_undiscovered
if @update_existing
this["updates"].each do |existing_update|
if config_drift[ConfigDriftStatus::ALREADY_IN].any? [existing_update["package-ecosystem"], existing_update["directory"]]
if existing_update["schedule"].is_a? Hash
new_interval = parsed_schedule_interval(existing_update["schedule"]["interval"])
existing_update["schedule"]["interval"] = new_interval
if existing_update["schedule"]["interval"] != "weekly"
existing_update["schedule"].delete("day")
end
else
existing_update["schedule"] = { "interval" => parsed_schedule_interval("monthly") }
end
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
|