Skip to content

Commit

Permalink
Fixes GH issue description, improves error reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
jeramysoucy committed Dec 27, 2023
1 parent 67643a7 commit c6f5ef6
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 49 deletions.
4 changes: 2 additions & 2 deletions lib/github/batch.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ module.exports = async (issues) => {
const headerText = 'This issue has been created automatically by [snyk-github-issue-creator](https://github.com/elastic/snyk-github-issue-creator).\r\n\r\nSnyk project(s):'
const projectText = projects
.map(
({ name, browseUrl, imageTag }) =>
`\r\n * [\`${name}\`](${browseUrl}) (manifest version ${imageTag})`
({ name, browseUrl }) =>
`\r\n * [\`${name}\`](${browseUrl})`
)
.join('')
const sectionText = Object.keys(sevMap)
Expand Down
30 changes: 20 additions & 10 deletions lib/github/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,30 @@ module.exports = {
},

// retrieve issue IDs already created in GitHub
async existingIssues () {
return await octokit.paginate(
`GET /search/issues?q=repo%3A${conf.ghOwner}/${conf.ghRepo}+is%3Aissue+label%3Asnyk`,
(response) =>
response.data.map((existingIssue) => [
existingIssue.title,
existingIssue.number
])
)
async existingIssues() {
try {
return await octokit.paginate(
`GET /search/issues?q=repo%3A${conf.ghOwner}/${conf.ghRepo}+is%3Aissue+label%3Asnyk`,
(response) =>
response.data.map((existingIssue) => [
existingIssue.title,
existingIssue.number
])
)
}
catch (err) {
throw new Error(`Failed to paginate octakit request for existing issues in repository ${conf.ghRepo}, error: ${err.message}`, { cause: err })
}
},

async createIssue (options) {
if (conf.dryRun) return
return await this.client.issues.create(options)
try {
return await this.client.issues.create(options)
}
catch (err) {
throw new Error(`Failed to ${options.issue_number?'update':'create'} issue: ${options.issue_number?options.issue_number:options.title}, error: ${err.message}`, { cause: err })
}
},

async createIssues (issues, existingIssues) {
Expand Down
51 changes: 32 additions & 19 deletions lib/github/labels.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,32 +50,45 @@ const getLabelAttributes = (name) => {

const ensureLabelsAreCreated = async (octokit, client, ghOwner, ghRepo, issues) => {
const labels = getLabels(issues)
const responseData = await octokit.paginate(
await client.issues.listLabelsForRepo({
owner: ghOwner,
repo: ghRepo,
per_page: 100
}),
(response) => response.data
)

let responseData
try {
responseData = await octokit.paginate(
await client.issues.listLabelsForRepo({
owner: ghOwner,
repo: ghRepo,
per_page: 100
}),
(response) => response.data
)
}
catch (err) {
throw new Error(`Failed to paginate octakit request for labels in repository ${ghRepo}, error: ${err.message}`, { cause: err })
}

const currentLabels = responseData.map((x) => x.name)
const labelsToCreate = labels.filter((x) => !currentLabels.includes(x))
if (!labelsToCreate.length || conf.dryRun) {
return
}

await Promise.all(
labelsToCreate.map((name) =>
client.issues
.createLabel({
owner: ghOwner,
repo: ghRepo,
...getLabelAttributes(name)
})
.then(() => {
console.log(`Created GitHub label: "${name}"`)
})
)
labelsToCreate.map((name) => {
try {
client.issues
.createLabel({
owner: ghOwner,
repo: ghRepo,
...getLabelAttributes(name)
})
.then(() => {
console.log(`Created GitHub label: "${name}"`)
})
}
catch (err) {
throw new Error(`Failed to create GitHub label '${name}', error: ${err.message}`, { cause: err })
}
})
)
}

Expand Down
65 changes: 47 additions & 18 deletions lib/snyk.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
const request = require('request-promise-native')

const baseV1Url = 'https://snyk.io/api/v1'
const baseRestUrl = 'https://api.snyk.io'
const baseRestUrl = 'https://api.snyk.io/rest'

module.exports = class Snyk {
constructor ({ token, orgId, minimumSeverity }) {
Expand All @@ -29,25 +29,49 @@ module.exports = class Snyk {
).orgs
}

async queryOrgInfo(organizationId) {
try {
const response = await request({
method: 'get',
url: `${baseRestUrl}/orgs/${organizationId}?version=2023-11-27`,
headers: this._headers,
json: true
})

if (response.data === undefined || response.data.attributes === undefined || response.data.attributes.name === undefined) {
throw new Error (`expected response to include data.attributes.name`)
}

return response.data
}
catch (err) {
throw new Error(`Failed to query snyk organization with id ${organizationId}, error: ${err.message}`, { cause: err })
}
}

async projects (orgId, selectedProjects = []) {
const organizationId = orgId || this._orgId

const organization = await this.queryOrgInfo(organizationId)

const responseData = await paginateRestResponseData(
`${baseRestUrl}/rest/orgs/${organizationId}/projects?version=2023-11-27&meta.latest_issue_counts=true&limit=20`,
`${baseRestUrl}/orgs/${organizationId}/projects?version=2023-11-27&meta.latest_issue_counts=true&limit=20`,
this._headers
)

return responseData.map((project) => {
const { critical, high, medium, low } = project.meta.latest_issue_counts
const issueCountTotal = critical + high + medium + low

return {
id: project.id,
name: project.attributes.name,
isMonitored:
project.attributes.status === 'active',
issueCountTotal
issueCountTotal,
browseUrl: `https://app.snyk.io/org/${organization.attributes.name.toLowerCase()}/project/${project.id}`,
}
}).filter(({ id, isMonitored, issueCountTotal }) => {
}).filter(({ id, isMonitored }) => {
if (selectedProjects.includes(id)) {
return true
}
Expand Down Expand Up @@ -98,19 +122,24 @@ function getSeverities (minimumSeverity) {
return ['critical', 'high', 'medium', 'low']
}

async function paginateRestResponseData (url, headers, method = 'get') {
const reponseData = []
do {
const response = await request({
method,
url,
headers,
json: true
})
reponseData.push(...response.data)
if (response.links.next) url = baseRestUrl + response.links.next
else url = undefined
} while (url)
async function paginateRestResponseData(url, headers, method = 'get') {
try {
const reponseData = []
do {
const response = await request({
method,
url,
headers,
json: true
})
reponseData.push(...response.data)
if (response.links.next) url = baseRestUrl + response.links.next / trimStart('/rest')
else url = undefined
} while (url)

return reponseData
return reponseData
}
catch (err) {
throw new Error(`Failed to paginate request for ${method} ${url}, error: ${err.message}`, { cause: err })
}
}

0 comments on commit c6f5ef6

Please sign in to comment.