-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathautoGenerateFields.js
More file actions
332 lines (260 loc) · 11.3 KB
/
autoGenerateFields.js
File metadata and controls
332 lines (260 loc) · 11.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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
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
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
document.addEventListener("DOMContentLoaded", function () {
setupFormHandler();
setupNotificationSystem();
});
// This works by creating an object with methods for different notification types of either error or success
// Calling either of these methods calls the main functionality, show(), which manipulates the notification element in HTML
// The show() method changes the element based on type and displays the message to the user
// The hide() function makes sure that the notification fades away after 5 seconds
const notificationSystem = {
show: function (message, type = 'error') {
const notification = document.getElementById('notification');
const notificationHeading = document.querySelector('.usa-alert__heading')
const messageElement = document.querySelector('.usa-alert__text');
messageElement.textContent = message;
if (type === 'error') {
notification.classList.add("usa-alert--error");
notificationHeading.textContent = "Error";
} else {
notification.classList.add("usa-alert--success");
notificationHeading.textContent = "Success";
}
notification.style.display = 'block';
setTimeout(() => {
notification.style.opacity = '1';
}, 10);
clearTimeout(this.timeout);
this.timeout = setTimeout(() => this.hide(), 5000);
},
hide: function () {
const notification = document.getElementById('notification');
notification.style.opacity = '0';
setTimeout(() => {
notification.style.display = 'none';
}, 500);
},
error: function (message) {
this.show(message, 'error');
},
success: function (message) {
this.show(message, 'success');
},
};
function setupNotificationSystem() {
const notification = document.getElementById('notification');
if (notification) {
notification.style.opacity = '0';
notification.style.transition = 'opacity 0.5s ease';
}
}
function setupFormHandler() {
const form = document.getElementById("github-url-form");
form.addEventListener("submit", async function (event) {
event.preventDefault();
const submitButton = document.getElementById("repo-url-button");
submitButton.value = "Loading...";
submitButton.disabled = true;
try {
const repoURL = document.getElementById("repo-url").value;
if (repoURL.length == 0) {
throw new Error("Please enter a GitHub repository URL");
}
const repoInfo = extractGitHubInfo(repoURL);
if (!repoInfo) {
throw new Error("Invalid GitHub URL format. Please enter a valid GitHub repository URL ->(https://github.com/username/repository)");
}
const repositoryInfo = await getRepoInformation(repoInfo);
const languages = await getRepoLanguages(repoInfo)
if (repositoryInfo) {
preFillFields(repositoryInfo, languages);
notificationSystem.success("Repository data loaded successfully!");
} else {
throw new Error("Could not fetch repository information. Please check the URL and try again.");
}
} catch (error) {
console.error(error.message);
notificationSystem.error(error.message);
} finally {
submitButton.value = "Submit";
submitButton.disabled = false;
}
});
}
function extractGitHubInfo(url) {
// Regex pattern to match GitHub URLs and extract org and repo
const regex = /(?:https?:\/\/)?(?:www\.)?github\.com\/([^\/]+)\/([^\/\s]+)/;
const match = url.match(regex);
if (match && match.length === 3) {
return {
organization: match[1],
repository: match[2]
};
}
return null;
}
async function getRepoInformation(repoInfo) {
const baseURL = "https://api.github.com/repos/";
const endpoint = `${baseURL}${repoInfo.organization}/${repoInfo.repository}`;
try {
const response = await fetch(endpoint);
if (!response.ok) {
throw new Error(`GitHub API error (${response.status}): ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error("Fetch error:", error.message);
}
}
async function getRepoLanguages(repoInfo) {
const endpoint = `https://api.github.com/repos/${repoInfo.organization}/${repoInfo.repository}/languages`
try {
const response = await fetch(endpoint);
if (!response.ok) {
throw new Error(`GitHub API error (${response.status}): ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error("Fetch error:", error.message);
}
}
async function getLicenseURL(repoURL) {
const urlParts = repoURL.replace('https://github.com/', '').split('/')
const owner = urlParts[0]
const repo = urlParts[1]
try {
const apiUrl = `https://api.github.com/repos/${owner}/${repo}/contents`
const response = await fetch(apiUrl)
const files = await response.json()
const licenseFile = files.find(file => {
const fileName = file.name.toLowerCase()
return fileName.startsWith('license')
})
if (licenseFile) {
return `${repoURL}/blob/main/${licenseFile.name}`
}
return `${repoURL}/blob/main/LICENSE`
} catch (error) {
console.error('Could not check license via API:', error.message)
return `${repoURL}/blob/main/LICENSE`
}
}
async function preFillFields(repoData, languages) {
if (!window.formIOInstance) {
notificationSystem.error("Form interface not initialized. Please refresh and try again.");
return;
}
try {
const form = window.formIOInstance
// Updating VCS to git - typically always be git
form.getComponent('vcs').setValue('git')
// Updating organization - only option available
form.getComponent('organization').setValue('Centers for Medicare & Medicaid Services')
// Updating visibility
form.getComponent('repositoryVisibility').setValue(repoData.private ? 'private' : 'public')
// Updating name
if (repoData.name) {
form.getComponent('name').setValue(repoData.name)
}
// Updating description
if (repoData.description) {
form.getComponent('description').setValue(repoData.description)
}
// Updating URL
if (repoData.html_url) {
if (repoData.private) {
// Private repositories must have "private" as their repositoryURL value
form.getComponent('repositoryURL').setValue("private")
}
else {
form.getComponent('repositoryURL').setValue(repoData.html_url)
}
}
// Updating forks
if (repoData.forks_count !== undefined) {
const reuseFrequencyComp = form.getComponent('reuseFrequency')
const currentReuse = {}
currentReuse.forks = repoData.forks_count
reuseFrequencyComp.setValue(currentReuse)
}
// Updating license object
if (repoData.license && repoData.license.spdx_id) {
const permissionsComp = form.getComponent('permissions');
const currentPermissions = permissionsComp.getValue() || {};
currentPermissions.licenses = currentPermissions.licenses || [];
const licenseURL = await getLicenseURL(repoData.html_url)
const licenseObj = {
name: repoData.license.spdx_id,
URL: licenseURL
};
currentPermissions.licenses = [licenseObj];
permissionsComp.setValue(currentPermissions);
}
// Update languages list by combining any the user has entered
if (form.getComponent('languages') && languages) {
const languagesComp = form.getComponent('languages')
const newLanguages = Object.keys(languages) || []
languagesComp.setValue(newLanguages)
}
// Update dates
if (repoData.created_at && repoData.updated_at) {
const dateComp = form.getComponent('date')
const currentDate = dateComp.getValue() || {}
currentDate.created = repoData.created_at;
currentDate.lastModified = repoData.updated_at
currentDate.metadataLastUpdated = new Date().toISOString()
dateComp.setValue(currentDate)
}
// Update tags
if (repoData.topics) {
const tagsComp = form.getComponent('tags')
const newTags = [...repoData.topics] || []
tagsComp.setValue(newTags)
}
// Update feedback mechanisms
if (repoData.html_url) {
const feedbackComp = form.getComponent('feedbackMechanism')
const issuesUrl = repoData.html_url + "/issues"
feedbackComp.setValue(issuesUrl)
}
// Update SBOM
if (form.getComponent('SBOM') && repoData.html_url) {
const upstreamComp = form.getComponent('SBOM');
const urlParts = repoData.html_url.split('/')
if (urlParts.length >= 2) {
const org = urlParts[urlParts.length - 2]
const repo = urlParts[urlParts.length - 1]
const dependenciesUrl = `https://github.com/${org}/${repo}/network/dependencies`
upstreamComp.setValue(dependenciesUrl)
}
}
// Update repositoryHost
if (form.getComponent('repositoryHost') && repoData.html_url) {
if (repoData.html_url.includes('github.cms.gov')) {
form.getComponent('repositoryHost').setValue('github.cms.gov')
} else if (repoData.html_url.includes('github.com/CMSgov')) {
form.getComponent('repositoryHost').setValue('github.com/CMSgov')
} else if (repoData.html_url.includes('github.com/CMS-Enterprise')) {
form.getComponent('repositoryHost').setValue('github.com/CMS-Enterprise')
} else if (repoData.html_url.includes('github.com/DSACMS')) {
form.getComponent('repositoryHost').setValue('github.com/DSACMS')
}
}
// fields to potentially automate
// clones, but this is only tracked for every 14 days
// status, by checking if its public, we can assume its production and check if its archival
// laborHours, by running a script? this might be harder since we need SCC
// maturityModel, we could check to see if certain files / sections live within a repo and make a guess like that
// usageType, by assuming that if its public = openSource and if private = governmnetWideReuse
notificationSystem.success("Repository data loaded successfully!")
} catch (error) {
notificationSystem.error("Error filling form fields with repository data. Please refresh and try again")
console.error("Form fill error:", error)
}
}
// This is global so we could use this throughout the website!
window.showErrorNotification = function (message) {
notificationSystem.error(message);
};
window.showSuccessNotification = function (message) {
notificationSystem.success(message);
};