Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to create Github issue with 'fixers' #1

Merged
merged 26 commits into from
Jun 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6b5cd72
Update package-lock after running npm install
JeroenKnoops Mar 16, 2021
0eee1bd
Update Gemfile.lock after bundle update
JeroenKnoops Mar 16, 2021
9b3117e
Add parse-domain
JeroenKnoops Mar 16, 2021
76cfa10
Update npm with npm update
JeroenKnoops Mar 16, 2021
901cd16
Add option to create Github issue with 'fixers'
Brend-Smits Mar 17, 2021
edc1925
Setup general logic flow - Check for existing issues on repo
Brend-Smits Mar 18, 2021
11c4bfd
Add properties to Schema & implemented logic for issue-create functio…
Brend-Smits Mar 18, 2021
4fbf659
Load Github PAT from environment 'GITHUB_TOKEN'
Brend-Smits Mar 19, 2021
4326c12
Remove hardcoded org/repo, you can set it via Env 'TARGET_REPO'
Brend-Smits Mar 19, 2021
29c242d
Refactor some functions - Add documentation and remove issueCreator
Brend-Smits Mar 19, 2021
c1eaca4
Refactor some functions - Add documentation and remove issueCreator
Brend-Smits Mar 19, 2021
5619718
Merge branch 'feature/github-issue-fix' of https://github.com/philips…
Brend-Smits Mar 19, 2021
a7937ca
Merge remote-tracking branch 'origin/update-deps' into feature/github…
Brend-Smits Mar 22, 2021
f87a87e
Update package-lock.json
Brend-Smits Mar 22, 2021
d1227fa
Might not be able to get user if user is an application
Brend-Smits Mar 23, 2021
6d19486
Set issueCreator to continuous-compliance-app and added debug log
Brend-Smits Mar 23, 2021
f4a1949
Make requests to endpoints instead of using helper octokit methods
Brend-Smits Mar 23, 2021
4699ab3
Debug
Brend-Smits Mar 23, 2021
85f7cc8
Fix issue where labels would not create properly
Brend-Smits Mar 23, 2021
c8f1734
Merge branch 'master' into feature/github-issue-fix
Brend-Smits Mar 26, 2021
301e90e
Happy linter == happy life
Brend-Smits Mar 26, 2021
fc66dca
Update packages to be from master + octokit + dotenv
Brend-Smits Mar 26, 2021
04cd379
add unit tests for github-issue-create fix
Brend-Smits Jun 20, 2021
91bfa50
Add additional helper tests and mock Github using Nock
Brend-Smits Jun 28, 2021
0d45fda
Happy Linter
Brend-Smits Jun 28, 2021
be23056
Merge branch 'master' into feature/github-issue-fix
Brend-Smits Jun 28, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,4 @@ DEPENDENCIES
wikicloth (~> 0.8.3)

BUNDLED WITH
2.1.4
2.2.14
7 changes: 6 additions & 1 deletion fixes/fixes.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
// Copyright 2017 TODO Group. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

module.exports = ['file-create', 'file-modify', 'file-remove']
module.exports = [
'file-create',
'file-modify',
'file-remove',
'github-issue-create'
]
28 changes: 28 additions & 0 deletions fixes/github-issue-create-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://raw.githubusercontent.com/philips-labs/repolinter/feature/github-issue-fix/fixes/github-issue-create-config.json",
"type": "object",
"properties": {
"issueLabels": {
"type": "array",
"items": { "type": "string" }
},
"issueBody": {
"type": "string"
},
"commentBody": {
"type": "string"
},
"issueTitle": {
"type": "string"
},
"bypassLabel": {
"type": "string",
"default": "CC: Bypass"
},
"uniqueRuleId": {
"type": "string"
}
},
"required": ["issueLabels", "bypassLabel", "issueBody", "commentBody", "issueTitle", "uniqueRuleId"]
}
237 changes: 237 additions & 0 deletions fixes/github-issue-create.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
// Copyright 2017 TODO Group. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

const Result = require('../lib/result')
const InternalHelpers = require('./helpers/github-issue-create-helpers')
// eslint-disable-next-line no-unused-vars
const { Octokit } = require('@octokit/rest')
let targetOrg = ''
let targetRepository = ''

/**
* Create a Github Issue on the targeted repository specifically for this broken rule.
*
* @param {FileSystem} fs A filesystem object configured with filter paths and target directories
* @param {object} options The rule configuration
* @param {string[]} targets The files to modify (will be overridden by options if present)
* @param {boolean} dryRun If true, repolinter will report suggested fixes, but will make no disk modifications.
* @returns {Promise<Result>} The fix result
*/
async function createGithubIssue(fs, options, targets, dryRun = false) {
try {
try {
await prepareWorkingEnvironment(dryRun)
} catch (error) {
return new Result(error.message, [], false)
}

// Create Labels
const labels = options.issueLabels
labels.push(options.bypassLabel)
await InternalHelpers.ensureAddedGithubLabels(
labels,
targetOrg,
targetRepository,
this.Octokit
)
options.issueLabels = options.issueLabels.filter(
label => label !== options.bypassLabel
)

// Find issues created by Repolinter
const issues = await InternalHelpers.findExistingRepolinterIssues(
options,
targetOrg,
targetRepository,
this.Octokit
)

// If there are no issues, create one.
// If there are issues, we loop through them and handle each each on it's own
if (issues === null || issues === undefined) {
// Issue should include the broken rule, a message in the body and a label.
const createdIssue = await createIssueOnGithub(options)
// We are done here, we created a new issue.
return new Result(
`No Open/Closed issues were found for this rule - Created new Github Issue with issue number - ${createdIssue.data.number}`,
[],
true
)
}

const openIssues = issues.filter(issue => issue.state === 'open')
for (let i = 0; i < openIssues.length; i++) {
const issue = openIssues[i]
// Issue is open, check body and find what rules have been broken.
// If the rule that has been broken, is already listed in the issue body/title, do nothing
const ruleIdentifier = InternalHelpers.retrieveRuleIdentifier(issue.body)
if (ruleIdentifier === options.uniqueRuleId) {
if (InternalHelpers.hasBypassLabelBeenApplied(options, issue.labels)) {
// Bypass label has been seen for this issue, we can ignore it.
return new Result(
`Rule fix failed as Github Issue ${issue.number} has bypass label.`,
[],
true
)
} else {
return new Result(
`No Github Issue Created - Issue already exists with correct unique identifier`,
[],
true
)
}
}
}

const closedIssues = issues.filter(issue => issue.state === 'closed')
for (let i = 0; i < closedIssues.length; i++) {
const issue = closedIssues[i]
const ruleIdentifier = InternalHelpers.retrieveRuleIdentifier(issue.body)

if (ruleIdentifier === options.uniqueRuleId) {
// This means that there is regression, we should update the issue with new body and comment on it.
if (InternalHelpers.hasBypassLabelBeenApplied(options, issue.labels)) {
// Bypass label has been seen for this issue, we can ignore it.
return new Result(
`Rule fix failed as Github Issue ${issue.number} has bypass label.`,
[],
true
)
} else {
await updateIssueOnGithub(options, issue.number)
await commentOnGithubIssue(options, issue.number)
return new Result(
`Github Issue ${issue.number} re-opened as there seems to be regression!`,
[],
true
)
}
} else {
console.log(
'Issue: ' + issue.number + ' - No matching rule identifier was found'
)
}
}
// There are open/closed issues from Continuous Compliance, but non of them are for this ruleset
// Issue should include the broken rule, a message in the body and a label.
const newIssue = await createIssueOnGithub(options)
return new Result(
`Github Issue ${newIssue.data.number} Created!`,
targets,
true
)
} catch (e) {
console.error(e)
}
}

/**
* Create an issue on Github with labels and all on the target repository.
*
* @param {object} options The rule configuration.
* @returns {object} Returns issue after adding it via the Github API.
*/
async function createIssueOnGithub(options) {
try {
const issueBodyWithId = options.issueBody.concat(
`\n Unique rule set ID: ${options.uniqueRuleId}`
)
return await this.Octokit.request('POST /repos/{owner}/{repo}/issues', {
owner: targetOrg,
repo: targetRepository,
title: options.issueTitle,
body: issueBodyWithId,
labels: options.issueLabels
})
} catch (e) {
console.error(e)
}
}

/**
* Update specific issue on Github.
*
* @param {object} options The rule configuration.
* @param {string} issueNumber The number of the issue we should update.
* @returns {object} Returns issue after updating it via the Github API.
*/
async function updateIssueOnGithub(options, issueNumber) {
try {
const issueBodyWithId = options.issueBody.concat(
`\n Unique rule set ID: ${options.uniqueRuleId}`
)
return await this.Octokit.request(
'PATCH /repos/{owner}/{repo}/issues/{issue_number}',
{
owner: targetOrg,
repo: targetRepository,
issue_number: issueNumber,
title: options.issueTitle,
body: issueBodyWithId,
labels: options.issueLabels,
state: 'open'
}
)
} catch (e) {
console.error(e)
}
}

/**
* Comment on a specific issue on Github.
*
* @param {object} options The rule configuration.
* @param {string} issueNumber The number of the issue we should update.
* @returns {object} Returns issue after commenting on it via the Github API.
*/
async function commentOnGithubIssue(options, issueNumber) {
try {
return await this.Octokit.request(
'POST /repos/{owner}/{repo}/issues/{issue_number}/comments',
{
owner: targetOrg,
repo: targetRepository,
issue_number: issueNumber,
body: options.commentBody
}
)
} catch (e) {
console.error(e)
}
}

/**
* Prepare our working environment.
* Check if environment variables are set.
* @param {string} dryRun Enable this if you want to test without configuring environment variables
* Set constants like targetOrg and targetRepository and initialize OctoKit.
*
*/
async function prepareWorkingEnvironment(dryRun) {
if (!dryRun) {
const targetRepoEnv = process.env.TARGET_REPO
const authTokenEnv = process.env.GITHUB_TOKEN
if (authTokenEnv === undefined || targetRepoEnv === undefined) {
throw new Error(
'Could not perform fix due to missing/invalid environment variables! Please set TARGET_REPO and GITHUB_TOKEN environment variables.'
)
}
targetOrg = targetRepoEnv.split('/')[0]
targetRepository = targetRepoEnv.split('/')[1]
this.Octokit = new Octokit({
auth: authTokenEnv,
baseUrl: 'https://api.github.com',
owner: targetOrg,
repo: targetRepository
})
} else {
targetOrg = 'test'
targetRepository = 'tester-repo'
this.Octokit = new Octokit({
auth: 'fake',
baseUrl: 'https://api.github.com'
})
}
}

module.exports = createGithubIssue
Loading