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

ci: add type checking to github scripts #9851

Merged
merged 3 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 7 additions & 5 deletions .github/scripts/addCalcitePackageLabel.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// @ts-check
const { createLabelIfMissing } = require("./support/utils");

/** @param {import('github-script').AsyncFunctionArguments} AsyncFunctionArguments */
module.exports = async ({ github, context }) => {
const { repo, owner } = context.repo;

const payload = /** @type {import('@octokit/webhooks-types').IssuesEvent} */ (context.payload);
const {
repo: { owner, repo },
payload: {
issue: { body, number: issue_number },
},
} = context;
issue: { body, number: issue_number },
} = payload;

if (!body) {
console.log("could not determine the issue body");
Expand Down
16 changes: 9 additions & 7 deletions .github/scripts/addEsriProductLabel.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
// @ts-check
const { createLabelIfMissing } = require("./support/utils");

/** @param {import('github-script').AsyncFunctionArguments} AsyncFunctionArguments */
module.exports = async ({ github, context }) => {
const { repo, owner } = context.repo;

const payload = /** @type {import('@octokit/webhooks-types').IssuesEvent} */ (context.payload);
const {
repo: { owner, repo },
payload: {
action,
issue: { body, number: issue_number },
},
} = context;
action,
issue: { body, number: issue_number },
} = payload;

if (!body) {
console.log("could not determine the issue body");
Expand All @@ -28,7 +30,7 @@ module.exports = async ({ github, context }) => {

const product = (productRegexMatch && productRegexMatch[0] ? productRegexMatch[0] : "").trim();

if (product && product !== "N/A") {
if (product !== "N/A") {
await createLabelIfMissing({
github,
context,
Expand Down
14 changes: 8 additions & 6 deletions .github/scripts/addPriorityLabel.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
// @ts-check
const { createLabelIfMissing } = require("./support/utils");

/** @param {import('github-script').AsyncFunctionArguments} AsyncFunctionArguments */
module.exports = async ({ github, context }) => {
const { repo, owner } = context.repo;

const payload = /** @type {import('@octokit/webhooks-types').IssuesEvent} */ (context.payload);
const {
repo: { owner, repo },
payload: {
action,
issue: { body, number: issue_number },
},
} = context;
action,
issue: { body, number: issue_number },
} = payload;

if (!body) {
console.log("could not determine the issue body");
Expand Down
27 changes: 20 additions & 7 deletions .github/scripts/assignForVerification.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,38 @@
// @ts-check
const { handoff, issueWorkflow } = require("./support/resources");
const { removeLabel } = require("./support/utils");

/** @param {import('github-script').AsyncFunctionArguments} AsyncFunctionArguments */
module.exports = async ({ github, context }) => {
const { repo, owner } = context.repo;

const payload = /** @type {import('@octokit/webhooks-types').IssuesLabeledEvent} */ (context.payload);
const {
label,
issue: { number },
} = payload;

const { ISSUE_VERIFIERS, CALCITE_DESIGNERS } = process.env;
const { label } = context.payload;

if (label && label.name === issueWorkflow.installed) {
if (label?.name === issueWorkflow.installed) {
const issueProps = {
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
owner,
repo,
issue_number: number,
};

const { data: issue } = await github.rest.issues.get(issueProps);

await removeLabel({ github, context, label: issueWorkflow.inDevelopment });

const assignees = ISSUE_VERIFIERS.split(",").map((v) => v.trim());
const assignees = ISSUE_VERIFIERS?.split(",").map((v) => v.trim());

// assign designers if figma updates are required
if (issue.labels.map((label) => label.name).includes(handoff.figmaChanges)) {
if (
assignees &&
CALCITE_DESIGNERS &&
issue.labels.map((label) => (typeof label === "string" ? label : label.name)).includes(handoff.figmaChanges)
) {
assignees.push(...CALCITE_DESIGNERS.split(",").map((v) => v.trim()));
}

Expand Down
19 changes: 13 additions & 6 deletions .github/scripts/assignPullRequestAuthor.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
// @ts-check
/** @param {import('github-script').AsyncFunctionArguments} AsyncFunctionArguments */
module.exports = async ({ github, context }) => {
const { repo, owner } = context.repo;

const payload = /** @type {import('@octokit/webhooks-types').PullRequestEvent} */ (context.payload);
const {
assignees,
number,
user: { login: author },
} = context.payload.pull_request;
pull_request: {
assignees,
number,
user: { login: author },
},
} = payload;

const updatedAssignees =
assignees && assignees.length ? [...assignees.map((a) => a.login).filter((a) => a !== author), author] : [author];

try {
await github.rest.issues.addAssignees({
owner: context.repo.owner,
repo: context.repo.repo,
owner,
repo,
issue_number: number,
assignees: updatedAssignees,
});
Expand Down
16 changes: 13 additions & 3 deletions .github/scripts/labelPullRequestWithCommitType.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
// @ts-check
const { issueType } = require("./support/resources");

/** @param {import('github-script').AsyncFunctionArguments} AsyncFunctionArguments */
module.exports = async ({ github, context }) => {
const { title, number } = context.payload.pull_request;
const { repo, owner } = context.repo;

const payload = /** @type {import('@octokit/webhooks-types').PullRequestEvent} */ (context.payload);
const {
pull_request: { title, number },
} = payload;

const conventionalCommitRegex =
/^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\([\w ,-]+\))?(!?:\s+)([\w ]+[\s\S]*)/i;
Expand All @@ -23,16 +30,19 @@ module.exports = async ({ github, context }) => {

try {
await github.rest.issues.addLabels({
owner,
repo,
issue_number: number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: [typeLabel],
});
} catch (e) {
console.error("Unable to label pull request, the author likely does not have write permissions\n", e);
}
};

/**
* @param {string} type
*/
function getLabelName(type) {
switch (type) {
case "feat":
Expand Down
26 changes: 21 additions & 5 deletions .github/scripts/notifyAboutNewComponent.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,32 @@
// @ts-check
// If the "new component" label is added to an issue, generates a notification to the Calcite designer lead(s)
// The secret is formatted like so: designer1, designer2, designer3
// Note the script automatically adds the "@" character in to notify the designer lead(s)

/** @param {import('github-script').AsyncFunctionArguments} AsyncFunctionArguments */
module.exports = async ({ github, context }) => {
const { designers } = process.env;
const { repo, owner } = context.repo;

const payload = /** @type {import('@octokit/webhooks-types').IssuesLabeledEvent} */ (context.payload);
const {
issue: { number },
} = payload;

const { DESIGNERS } = process.env;

// Add a "@" character to notify the user
const calcite_designers = designers.split(",").map((v) => " @" + v.trim());
const calcite_designers = DESIGNERS?.split(",").map((v) => " @" + v.trim());

if (!calcite_designers?.length) {
console.error("unable to determine designers");
process.exit(1);
}

// Add a comment to issues with the 'new component' label to notify the designer(s)
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
owner,
repo,
issue_number: number,
body: `cc ${calcite_designers}`,
});
};
23 changes: 16 additions & 7 deletions .github/scripts/notifyWhenReadyForDev.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @ts-check
// When the "ready for dev" label is added to an issue:
// 1. Modifies the labels,
// 2. Updates the assignees and milestone, and
Expand All @@ -9,18 +10,26 @@
const { issueWorkflow, planning } = require("./support/resources");
const { removeLabel } = require("./support/utils");

/** @param {import('github-script').AsyncFunctionArguments} AsyncFunctionArguments */
module.exports = async ({ github, context }) => {
const { managers } = process.env;
const { label } = context.payload;
const { repo, owner } = context.repo;

if (label && label.name === "ready for dev") {
const payload = /** @type {import('@octokit/webhooks-types').IssuesLabeledEvent} */ (context.payload);
const {
issue: { number },
label,
} = payload;

const { MANAGERS } = process.env;

if (label?.name === "ready for dev") {
// Add a "@" character to notify the user
const calcite_managers = managers.split(",").map((v) => " @" + v.trim());
const calcite_managers = MANAGERS?.split(",").map((v) => " @" + v.trim());

const issueProps = {
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
owner,
repo,
issue_number: number,
};

/* Modify labels */
Expand Down
23 changes: 16 additions & 7 deletions .github/scripts/notifyWhenSpikeComplete.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @ts-check
// When the "spike complete" label is added to an issue:
// 1. Modifies the labels,
// 2. Updates the assignees and milestone, and
Expand All @@ -9,18 +10,26 @@
const { issueWorkflow, planning } = require("./support/resources");
const { removeLabel } = require("./support/utils");

/** @param {import('github-script').AsyncFunctionArguments} AsyncFunctionArguments */
module.exports = async ({ github, context }) => {
const { managers } = process.env;
const { label } = context.payload;
const { repo, owner } = context.repo;

if (label && label.name === planning.spikeComplete) {
const payload = /** @type {import('@octokit/webhooks-types').IssuesLabeledEvent} */ (context.payload);
const {
issue: { number },
label,
} = payload;

const { MANAGERS } = process.env;

if (label?.name === planning.spikeComplete) {
// Add a "@" character to notify the user
const calcite_managers = managers.split(",").map((v) => " @" + v.trim());
const calcite_managers = MANAGERS?.split(",").map((v) => " @" + v.trim());

const issueProps = {
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
owner,
repo,
issue_number: number,
};

/* Modify labels */
Expand Down
19 changes: 19 additions & 0 deletions .github/scripts/support/utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
// @ts-check
module.exports = {
/**
* @typedef {object} removeLabelParam
* @property {InstanceType<typeof import('@actions/github/lib/utils').GitHub>} github
* @property {import('@actions/github/lib/context').Context} context
* @property {string} label
*
* @param {removeLabelParam} obj
**/
removeLabel: async ({ github, context, label }) => {
const { owner, repo } = context.repo;
const issue_number = context.issue.number;
Expand All @@ -15,6 +24,16 @@ module.exports = {
}
},

/**
* @typedef {object} createLabelIfMissingParam
* @property {InstanceType<typeof import('@actions/github/lib/utils').GitHub>} github
* @property {import('@actions/github/lib/context').Context} context
* @property {string} label
* @property {string} color
* @property {string} description
*
* @param {createLabelIfMissingParam} obj
**/
createLabelIfMissing: async ({ github, context, label, color, description }) => {
const { owner, repo } = context.repo;
try {
Expand Down
14 changes: 11 additions & 3 deletions .github/scripts/validatePullRequestTitle.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
// @ts-check
/** @param {import('github-script').AsyncFunctionArguments} AsyncFunctionArguments */
module.exports = async ({ context, core }) => {
const payload = /** @type {import('@octokit/webhooks-types').PullRequestEvent} */ (context.payload);
const { title } = payload.pull_request;

const REGEX = new RegExp("^[^…]+$"); // Title must match this regex
const MIN_LENGTH = 1; // Min length of the title
const MAX_LENGTH = -1; // Max length of the title (-1 is no max)
const ALLOWED_PREFIXES = []; // Title must start with one of these prefixes
const DISALLOWED_PREFIXES = []; // Title cannot start with one of these prefixes
const PREFIX_CASE_SENSITIVE = false; // Whether the prefix is case sensitive

/**
* @param {string} title
* @param {string} prefix
*/
const validateTitlePrefix = (title, prefix) =>
PREFIX_CASE_SENSITIVE ? title.startsWith(prefix) : title.toLowerCase().startsWith(prefix.toLowerCase());

const { title } = context.payload.pull_request;
if (!REGEX.test(title)) {
core.setFailed(`Pull Request title "${title}" failed to match regex - ${REGEX}`);
return;
Expand All @@ -28,15 +36,15 @@ module.exports = async ({ context, core }) => {
core.info(`Allowed Prefixes: ${ALLOWED_PREFIXES}`);
if (ALLOWED_PREFIXES.length && !ALLOWED_PREFIXES.some((prefix) => validateTitlePrefix(title, prefix))) {
core.setFailed(
`Pull Request title "${title}" did not start with any of the required prefixes - ${ALLOWED_PREFIXES}`
`Pull Request title "${title}" did not start with any of the required prefixes - ${ALLOWED_PREFIXES}`,
);
return;
}

core.info(`Disallowed Prefixes: ${DISALLOWED_PREFIXES}`);
if (DISALLOWED_PREFIXES.length && DISALLOWED_PREFIXES.some((prefix) => validateTitlePrefix(title, prefix))) {
core.setFailed(
`Pull Request title "${title}" started with one of the disallowed prefixes - ${DISALLOWED_PREFIXES}`
`Pull Request title "${title}" started with one of the disallowed prefixes - ${DISALLOWED_PREFIXES}`,
);
return;
}
Expand Down
Loading
Loading