-
Notifications
You must be signed in to change notification settings - Fork 83
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
413 additions
and
369 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,4 +8,4 @@ coverage: | |
default: | ||
threshold: 3 | ||
|
||
comment: false | ||
comment: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,4 +50,4 @@ | |
"<rootDir>/tests/**/*.test.(ts|js)" | ||
] | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,126 +1,155 @@ | ||
import * as core from '@actions/core' | ||
import { Toolkit } from 'actions-toolkit' | ||
import fm from 'front-matter' | ||
import nunjucks from 'nunjucks' | ||
import * as core from "@actions/core"; | ||
import { Toolkit } from "actions-toolkit"; | ||
import fm from "front-matter"; | ||
import nunjucks from "nunjucks"; | ||
// @ts-expect-error | ||
import dateFilter from 'nunjucks-date-filter' | ||
import { ZodError } from 'zod' | ||
import { FrontMatterAttributes, frontmatterSchema, listToArray, setOutputs } from './helpers' | ||
|
||
function logError(tools: Toolkit, template: string, action: 'creating' | 'updating' | 'parsing', err: any) { | ||
import dateFilter from "nunjucks-date-filter"; | ||
import { ZodError } from "zod"; | ||
import { | ||
FrontMatterAttributes, | ||
frontmatterSchema, | ||
listToArray, | ||
setOutputs, | ||
} from "./helpers"; | ||
|
||
function logError( | ||
tools: Toolkit, | ||
template: string, | ||
action: "creating" | "updating" | "parsing", | ||
err: any | ||
) { | ||
// Log the error message | ||
const errorMessage = `An error occurred while ${action} the issue. This might be caused by a malformed issue title, or a typo in the labels or assignees. Check ${template}!` | ||
tools.log.error(errorMessage) | ||
tools.log.error(err) | ||
const errorMessage = `An error occurred while ${action} the issue. This might be caused by a malformed issue title, or a typo in the labels or assignees. Check ${template}!`; | ||
tools.log.error(errorMessage); | ||
tools.log.error(err); | ||
|
||
// The error might have more details | ||
if (err.errors) tools.log.error(err.errors) | ||
if (err.errors) tools.log.error(err.errors); | ||
|
||
// Exit with a failing status | ||
core.setFailed(errorMessage + '\n\n' + err.message) | ||
return tools.exit.failure() | ||
core.setFailed(errorMessage + "\n\n" + err.message); | ||
return tools.exit.failure(); | ||
} | ||
|
||
export async function createAnIssue (tools: Toolkit) { | ||
const template = tools.inputs.filename || '.github/ISSUE_TEMPLATE.md' | ||
const assignees = tools.inputs.assignees | ||
export async function createAnIssue(tools: Toolkit) { | ||
const template = tools.inputs.filename || ".github/ISSUE_TEMPLATE.md"; | ||
const assignees = tools.inputs.assignees; | ||
|
||
let updateExisting: Boolean | null = null | ||
let updateExisting: Boolean | null = null; | ||
if (tools.inputs.update_existing) { | ||
if (tools.inputs.update_existing === 'true') { | ||
updateExisting = true | ||
} else if (tools.inputs.update_existing === 'false') { | ||
updateExisting = false | ||
if (tools.inputs.update_existing === "true") { | ||
updateExisting = true; | ||
} else if (tools.inputs.update_existing === "false") { | ||
updateExisting = false; | ||
} else { | ||
tools.exit.failure(`Invalid value update_existing=${tools.inputs.update_existing}, must be one of true or false`) | ||
tools.exit.failure( | ||
`Invalid value update_existing=${tools.inputs.update_existing}, must be one of true or false` | ||
); | ||
} | ||
} | ||
|
||
const env = nunjucks.configure({ autoescape: false }) | ||
env.addFilter('date', dateFilter) | ||
const env = nunjucks.configure({ autoescape: false }); | ||
env.addFilter("date", dateFilter); | ||
|
||
const templateVariables = { | ||
...tools.context, | ||
repo: tools.context.repo, | ||
env: process.env, | ||
date: Date.now() | ||
} | ||
date: Date.now(), | ||
}; | ||
|
||
// Get the file | ||
tools.log.debug('Reading from file', template) | ||
const file = await tools.readFile(template) as string | ||
tools.log.debug("Reading from file", template); | ||
const file = (await tools.readFile(template)) as string; | ||
|
||
// Grab the front matter as JSON | ||
const { attributes: rawAttributes, body } = fm<FrontMatterAttributes>(file) | ||
const { attributes: rawAttributes, body } = fm<FrontMatterAttributes>(file); | ||
|
||
let attributes: FrontMatterAttributes | ||
let attributes: FrontMatterAttributes; | ||
try { | ||
attributes = await frontmatterSchema.parseAsync(rawAttributes) | ||
attributes = await frontmatterSchema.parseAsync(rawAttributes); | ||
} catch (err) { | ||
if (err instanceof ZodError) { | ||
const formatted = err.format() | ||
return logError(tools, template, 'parsing', formatted) | ||
const formatted = err.format(); | ||
return logError(tools, template, "parsing", formatted); | ||
} | ||
throw err | ||
throw err; | ||
} | ||
|
||
tools.log(`Front matter for ${template} is`, attributes) | ||
tools.log(`Front matter for ${template} is`, attributes); | ||
|
||
const templated = { | ||
body: env.renderString(body, templateVariables), | ||
title: env.renderString(attributes.title, templateVariables) | ||
} | ||
tools.log.debug('Templates compiled', templated) | ||
title: env.renderString(attributes.title, templateVariables), | ||
}; | ||
tools.log.debug("Templates compiled", templated); | ||
|
||
if (updateExisting !== null) { | ||
tools.log.info(`Fetching issues with title "${templated.title}"`) | ||
tools.log.info(`Fetching issues with title "${templated.title}"`); | ||
|
||
let query = `is:issue repo:${process.env.GITHUB_REPOSITORY} in:title "${templated.title.replace(/['"]/g, "\\$&")}"` | ||
let query = `is:issue repo:${ | ||
process.env.GITHUB_REPOSITORY | ||
} in:title "${templated.title.replace(/['"]/g, "\\$&")}"`; | ||
|
||
const searchExistingType = tools.inputs.search_existing || 'open' | ||
const allowedStates = ['open', 'closed'] | ||
const searchExistingType = tools.inputs.search_existing || "open"; | ||
const allowedStates = ["open", "closed"]; | ||
if (allowedStates.includes(searchExistingType)) { | ||
query += ` is:${searchExistingType}` | ||
query += ` is:${searchExistingType}`; | ||
} | ||
|
||
const existingIssues = await tools.github.search.issuesAndPullRequests({ q: query }) | ||
const existingIssue = existingIssues.data.items.find(issue => issue.title === templated.title) | ||
const existingIssues = await tools.github.search.issuesAndPullRequests({ | ||
q: query, | ||
}); | ||
const existingIssue = existingIssues.data.items.find( | ||
(issue) => issue.title === templated.title | ||
); | ||
if (existingIssue) { | ||
if (updateExisting === false) { | ||
tools.exit.success(`Existing issue ${existingIssue.title}#${existingIssue.number}: ${existingIssue.html_url} found but not updated`) | ||
tools.exit.success( | ||
`Existing issue ${existingIssue.title}#${existingIssue.number}: ${existingIssue.html_url} found but not updated` | ||
); | ||
} else { | ||
try { | ||
tools.log.info(`Updating existing issue ${existingIssue.title}#${existingIssue.number}: ${existingIssue.html_url}`) | ||
tools.log.info( | ||
`Updating existing issue ${existingIssue.title}#${existingIssue.number}: ${existingIssue.html_url}` | ||
); | ||
const issue = await tools.github.issues.update({ | ||
...tools.context.repo, | ||
issue_number: existingIssue.number, | ||
body: templated.body | ||
}) | ||
setOutputs(tools, issue.data) | ||
tools.exit.success(`Updated issue ${existingIssue.title}#${existingIssue.number}: ${existingIssue.html_url}`) | ||
body: templated.body, | ||
}); | ||
setOutputs(tools, issue.data); | ||
tools.exit.success( | ||
`Updated issue ${existingIssue.title}#${existingIssue.number}: ${existingIssue.html_url}` | ||
); | ||
} catch (err: any) { | ||
return logError(tools, template, 'updating', err) | ||
return logError(tools, template, "updating", err); | ||
} | ||
} | ||
} else { | ||
tools.log.info('No existing issue found to update') | ||
tools.log.info("No existing issue found to update"); | ||
} | ||
} | ||
|
||
// Create the new issue | ||
tools.log.info(`Creating new issue ${templated.title}`) | ||
tools.log.info(`Creating new issue ${templated.title}`); | ||
try { | ||
const issue = await tools.github.issues.create({ | ||
...tools.context.repo, | ||
...templated, | ||
assignees: assignees ? listToArray(assignees) : listToArray(attributes.assignees), | ||
assignees: assignees | ||
? listToArray(assignees) | ||
: listToArray(attributes.assignees), | ||
labels: listToArray(attributes.labels), | ||
milestone: Number(tools.inputs.milestone || attributes.milestone) || undefined | ||
}) | ||
|
||
setOutputs(tools, issue.data) | ||
tools.log.success(`Created issue ${issue.data.title}#${issue.data.number}: ${issue.data.html_url}`) | ||
milestone: | ||
Number(tools.inputs.milestone || attributes.milestone) || undefined, | ||
}); | ||
|
||
setOutputs(tools, issue.data); | ||
tools.log.success( | ||
`Created issue ${issue.data.title}#${issue.data.number}: ${issue.data.html_url}` | ||
); | ||
} catch (err: any) { | ||
return logError(tools, template, 'creating', err) | ||
return logError(tools, template, "creating", err); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,26 @@ | ||
import { Toolkit } from 'actions-toolkit' | ||
import { z } from 'zod' | ||
import { Toolkit } from "actions-toolkit"; | ||
import { z } from "zod"; | ||
|
||
export const frontmatterSchema = z.object({ | ||
title: z.string(), | ||
assignees: z.union([z.array(z.string()), z.string()]).optional(), | ||
labels: z.union([z.array(z.string()), z.string()]).optional(), | ||
milestone: z.union([z.string(), z.number()]).optional() | ||
}).strict() | ||
export const frontmatterSchema = z | ||
.object({ | ||
title: z.string(), | ||
assignees: z.union([z.array(z.string()), z.string()]).optional(), | ||
labels: z.union([z.array(z.string()), z.string()]).optional(), | ||
milestone: z.union([z.string(), z.number()]).optional(), | ||
}) | ||
.strict(); | ||
|
||
export type FrontMatterAttributes = z.infer<typeof frontmatterSchema> | ||
export type FrontMatterAttributes = z.infer<typeof frontmatterSchema>; | ||
|
||
export function setOutputs (tools: Toolkit, issue: { number: number, html_url: string }) { | ||
tools.outputs.number = String(issue.number) | ||
tools.outputs.url = issue.html_url | ||
export function setOutputs( | ||
tools: Toolkit, | ||
issue: { number: number; html_url: string } | ||
) { | ||
tools.outputs.number = String(issue.number); | ||
tools.outputs.url = issue.html_url; | ||
} | ||
|
||
export function listToArray (list?: string[] | string) { | ||
if (!list) return [] | ||
return Array.isArray(list) ? list : list.split(', ') | ||
} | ||
export function listToArray(list?: string[] | string) { | ||
if (!list) return []; | ||
return Array.isArray(list) ? list : list.split(", "); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
import { Toolkit } from 'actions-toolkit' | ||
import { createAnIssue } from './action' | ||
import { Toolkit } from "actions-toolkit"; | ||
import { createAnIssue } from "./action"; | ||
|
||
Toolkit.run(createAnIssue, { | ||
secrets: ['GITHUB_TOKEN'] | ||
}) | ||
secrets: ["GITHUB_TOKEN"], | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
{ | ||
"repository": { | ||
"owner": { "login": "JasonEtco" }, | ||
"owner": { | ||
"login": "JasonEtco" | ||
}, | ||
"name": "waddup" | ||
} | ||
} | ||
} |
Oops, something went wrong.