@@ -9789,60 +9789,214 @@ const BUG_LABELS = ["bug::normal", "bug::regression"];
97899789
97909790const SEVERITY_LABELS = ["severity::s1", "severity::s2", "severity::s3"];
97919791
9792+ // Map semantic commit types to our label types
9793+ const SEMANTIC_TYPE_TO_LABEL = {
9794+ chore: "type::chore",
9795+ fix: "type::bug",
9796+ bug: "type::bug",
9797+ feat: "type::feature",
9798+ feature: "type::feature",
9799+ security: "type::security",
9800+ };
9801+
9802+ /**
9803+ * Extract semantic commit type from a message
9804+ * Supports formats like:
9805+ * - "feat: add new feature"
9806+ * - "fix(component): fix bug"
9807+ * - "chore: update dependencies"
9808+ * @param {string} message - The commit message or PR title
9809+ * @returns {string|null} - The semantic type or null if not found
9810+ */
9811+ function extractSemanticType(message) {
9812+ if (!message) return null;
9813+
9814+ core.debug(`Attempting to extract semantic type from: "${message}"`);
9815+
9816+ // Match standard semantic commit format: type(scope): message
9817+ const semanticRegex = /^(\w+)(?:\([\w-]+\))?:\s/;
9818+ const match = message.match(semanticRegex);
9819+
9820+ if (match && match[1]) {
9821+ const type = match[1].toLowerCase();
9822+ core.debug(`Extracted semantic type: "${type}"`);
9823+ return type;
9824+ }
9825+
9826+ core.debug("No semantic type found in message");
9827+ return null;
9828+ }
9829+
97929830async function run() {
97939831 try {
97949832 // get inputs
97959833 const token = core.getInput("token", { required: true });
9834+ core.debug("Token retrieved successfully");
97969835
97979836 // set up github client
97989837 const octokit = github.getOctokit(token);
9838+ core.debug("GitHub client initialized");
9839+
9840+ // Track if we added a label based on semantic commit
9841+ let addedSemanticLabel = false;
97999842
98009843 // fetch the list of labels
9844+ core.debug("Fetching current PR labels...");
98019845 const labels = (
98029846 await octokit.rest.issues.listLabelsOnIssue({
98039847 ...github.context.repo,
98049848 issue_number: github.context.issue.number,
98059849 })
98069850 ).data.map((label) => label.name);
9807- core.debug(`Found labels: ${labels.join(", ")}`);
9851+ core.debug(`Found ${labels.length} labels: ${labels.join(", ")}`);
9852+
9853+ // Get PR details to check for semantic commit messages
9854+ const prNumber = github.context.issue.number;
9855+ core.debug(`Processing PR #${prNumber}`);
9856+
9857+ core.debug("Fetching PR details...");
9858+ const { data: pullRequest } = await octokit.rest.pulls.get({
9859+ ...github.context.repo,
9860+ pull_number: prNumber,
9861+ });
9862+
9863+ // Get the PR title and HEAD commit message
9864+ const prTitle = pullRequest.title;
9865+ core.debug(`PR title: "${prTitle}"`);
9866+
9867+ // Get the HEAD commit message
9868+ core.debug("Fetching PR commits...");
9869+ const { data: commits } = await octokit.rest.pulls.listCommits({
9870+ ...github.context.repo,
9871+ pull_number: prNumber,
9872+ });
9873+
9874+ core.debug(`Found ${commits.length} commits in PR`);
9875+ const headCommitMessage = commits.length > 0 ? commits[commits.length - 1].commit.message : null;
9876+ if (headCommitMessage) {
9877+ core.debug(`HEAD commit message: "${headCommitMessage}"`);
9878+ } else {
9879+ core.debug("No HEAD commit message found");
9880+ }
9881+
9882+ // Try to extract semantic type from PR title or HEAD commit
9883+ core.debug("Extracting semantic type from PR title...");
9884+ const prTitleType = extractSemanticType(prTitle);
9885+
9886+ core.debug("Extracting semantic type from HEAD commit...");
9887+ const commitType = extractSemanticType(headCommitMessage);
9888+
9889+ // Use PR title type first, then fall back to commit type
9890+ const semanticType = prTitleType || commitType;
9891+ if (semanticType) {
9892+ core.debug(`Using semantic type: "${semanticType}"`);
9893+ } else {
9894+ core.debug("No semantic type found in PR title or HEAD commit");
9895+ }
9896+
9897+ // If we found a semantic type that maps to one of our labels, add it if not present
9898+ if (semanticType && SEMANTIC_TYPE_TO_LABEL[semanticType]) {
9899+ const labelToAdd = SEMANTIC_TYPE_TO_LABEL[semanticType];
9900+ core.debug(`Semantic type "${semanticType}" maps to label "${labelToAdd}"`);
9901+
9902+ // Only add the label if it's not already present
9903+ if (!labels.includes(labelToAdd)) {
9904+ core.info(`Adding label ${labelToAdd} based on semantic commit type: ${semanticType}`);
9905+
9906+ core.debug("Calling GitHub API to add label...");
9907+ await octokit.rest.issues.addLabels({
9908+ ...github.context.repo,
9909+ issue_number: prNumber,
9910+ labels: [labelToAdd],
9911+ });
9912+ core.debug("Label added successfully via API");
9913+
9914+ // Update our local labels array to include the new label
9915+ labels.push(labelToAdd);
9916+ addedSemanticLabel = true;
9917+ core.debug(`Updated local labels array: ${labels.join(", ")}`);
9918+
9919+ // If we just added a label, give it time to apply
9920+ if (addedSemanticLabel) {
9921+ core.info("Added label based on semantic commit message. Waiting for label to apply...");
9922+ // Short delay to allow the label to be properly registered
9923+ core.debug("Waiting 2 seconds for label to propagate...");
9924+ await new Promise(resolve => setTimeout(resolve, 2000));
9925+ core.debug("Wait completed");
9926+
9927+ // Refetch the labels to ensure we have the most up-to-date set
9928+ core.info("Refetching labels after adding semantic label...");
9929+ core.debug("Calling GitHub API to get updated labels...");
9930+ const updatedLabelsResponse = await octokit.rest.issues.listLabelsOnIssue({
9931+ ...github.context.repo,
9932+ issue_number: github.context.issue.number,
9933+ });
9934+
9935+ // Update our labels array with the freshly fetched labels
9936+ const updatedLabels = updatedLabelsResponse.data.map((label) => label.name);
9937+ core.debug(`Refetched ${updatedLabels.length} labels: ${updatedLabels.join(", ")}`);
9938+
9939+ // Replace our labels array with the updated one
9940+ labels.length = 0;
9941+ updatedLabels.forEach(label => labels.push(label));
9942+ core.debug(`Updated local labels array after refetch: ${labels.join(", ")}`);
9943+ }
9944+ } else {
9945+ core.debug(`Label "${labelToAdd}" already exists on PR, no need to add it`);
9946+ }
9947+ } else if (semanticType) {
9948+ core.debug(`Semantic type "${semanticType}" does not map to any of our labels`);
9949+ }
98089950
98099951 // ensure exactly one primary label is set
9952+ core.debug("Checking for primary labels...");
98109953 const primaryLabels = PRIMARY_LABELS.filter((label) =>
98119954 labels.includes(label)
98129955 );
9813- core.debug(`Found primary labels: ${primaryLabels.join(", ")}`);
9956+ core.debug(`Found ${primaryLabels.length} primary labels: ${primaryLabels.join(", ")}`);
9957+
98149958 if (primaryLabels.length !== 1) {
9959+ core.debug(`Primary label check failed: found ${primaryLabels.length} primary labels`);
98159960 throw new Error(
98169961 `Exactly one primary label must be set from [${PRIMARY_LABELS.join(", ")}]. Found: ${primaryLabels.join(", ")}`
98179962 );
98189963 }
9964+ core.debug("Primary label check passed");
98199965
98209966 // if the primary label is a bug, ensure a bug label is set
98219967 if (primaryLabels[0] === "type::bug") {
9968+ core.debug("Primary label is type::bug, checking for bug labels...");
98229969 const bugLabels = BUG_LABELS.filter((label) => labels.includes(label));
9823- core.debug(`type::bug is set, found bug labels: ${bugLabels.join(", ")}`);
9970+ core.debug(`Found ${bugLabels.length} bug labels: ${bugLabels.join(", ")}`);
98249971 if (bugLabels.length !== 1) {
9972+ core.debug(`Bug label check failed: found ${bugLabels.length} bug labels`);
98259973 throw new Error(
98269974 `Exactly one bug label must be set for primary type::bug. Found: ${bugLabels.join(
98279975 ", "
98289976 )}`
98299977 );
98309978 }
9979+ core.debug("Bug label check passed");
98319980 }
98329981
98339982 // ensure no more than one severity label is set
9983+ core.debug("Checking for severity labels...");
98349984 const severityLabels = SEVERITY_LABELS.filter((label) =>
98359985 labels.includes(label)
98369986 );
9837- core.debug(`Found severity labels: ${severityLabels.join(", ")}`);
9987+ core.debug(`Found ${severityLabels.length} severity labels: ${severityLabels.join(", ")}`);
98389988 if (severityLabels.length > 1) {
9989+ core.debug(`Severity label check failed: found ${severityLabels.length} severity labels`);
98399990 throw new Error(
98409991 `No more than one severity label may be set. Found: ${severityLabels.join(
98419992 ", "
98429993 )}`
98439994 );
98449995 }
9996+ core.debug("Severity label check passed");
9997+
98459998 } catch (error) {
9999+ core.debug(`Error caught: ${error.message}`);
984610000 if (error instanceof Error) core.setFailed(error.message);
984710001 }
984810002}
0 commit comments