Skip to content
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
97 changes: 97 additions & 0 deletions scripts/agents/includes/__tests__/labeler-utils.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
const {
matchesBranchPattern,
matchesFilePatterns,
determineLabelsFromRules,
} = require("../labeler-utils.js");
Comment on lines +1 to +5
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Since labeler-utils.js is an ES module (using import/export syntax), using CommonJS require to load it will fail at runtime in standard Node.js environments with ERR_REQUIRE_ESM. To ensure compatibility and consistency with the rest of the codebase, use ES module import syntax instead.

Suggested change
const {
matchesBranchPattern,
matchesFilePatterns,
determineLabelsFromRules,
} = require("../labeler-utils.js");
import {
matchesBranchPattern,
matchesFilePatterns,
determineLabelsFromRules,
} from "../labeler-utils.js";


describe("labeler-utils", () => {
describe("matchesBranchPattern", () => {
test("matches regex and glob patterns", () => {
expect(matchesBranchPattern("feat/new-flow", ["^feat/.*"])).toBe(true);
expect(matchesBranchPattern("docs/readme", ["docs/*"])).toBe(true);
expect(matchesBranchPattern("fix/bug", ["^feat/.*", "docs/*"])).toBe(
false,
);
});

test("returns false for invalid regex patterns", () => {
expect(matchesBranchPattern("feat/new-flow", ["^(feat"])).toBe(false);
});
});

describe("matchesFilePatterns", () => {
const changedFiles = [
".github/workflows/labeling.yml",
"docs/ISSUE_LABELS.md",
"scripts/agents/labeling.agent.js",
];

test("supports any-glob-to-any-file", () => {
const config = {
"any-glob-to-any-file": [".github/workflows/**", "src/**"],
};
expect(matchesFilePatterns(changedFiles, config)).toBe(true);
});

test("supports all-globs-to-all-files", () => {
const config = {
"all-globs-to-all-files": [".github/workflows/**", "docs/**"],
};
expect(matchesFilePatterns(changedFiles, config)).toBe(true);
});
Comment on lines +36 to +41
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The test for all-globs-to-all-files expects true even though changedFiles contains scripts/agents/labeling.agent.js, which does not match either of the configured glob patterns (.github/workflows/** or docs/**). This test only passes because the underlying implementation of all-globs-to-all-files in labeler-utils.js (line 110) incorrectly uses changedFiles.some instead of changedFiles.every. In a standard GitHub Actions labeler, all-globs-to-all-files requires that all changed files match the glob patterns. To fix this, the test should be updated to use a set of files and patterns where all files actually match the patterns, and the underlying implementation in labeler-utils.js should be corrected to use every instead of some.

Suggested change
test("supports all-globs-to-all-files", () => {
const config = {
"all-globs-to-all-files": [".github/workflows/**", "docs/**"],
};
expect(matchesFilePatterns(changedFiles, config)).toBe(true);
});
test("supports all-globs-to-all-files", () => {
const config = {
"all-globs-to-all-files": ["docs/**"],
};
const docsOnlyFiles = ["docs/ISSUE_LABELS.md", "docs/ISSUE_TYPES.md"];
expect(matchesFilePatterns(docsOnlyFiles, config)).toBe(true);
});


test("supports any-glob-to-all-files", () => {
const markdownFiles = ["docs/ISSUE_LABELS.md", "docs/ISSUE_TYPES.md"];
const config = {
"any-glob-to-all-files": ["docs/**/*.md", "scripts/**/*.js"],
};
expect(matchesFilePatterns(markdownFiles, config)).toBe(true);
});
});

describe("determineLabelsFromRules", () => {
test("applies branch and file labels exactly once", () => {
const context = {
payload: {
pull_request: {
number: 427,
head: { ref: "feat/label-hardening" },
},
},
};

const labelerRules = {
"type:feature": {
"head-branch": ["^feat/.*"],
},
"area:ci": {
"changed-files": {
"any-glob-to-any-file": [".github/workflows/**"],
},
},
"area:labels": {
"head-branch": ["^feat/.*"],
"changed-files": {
"any-glob-to-any-file": ["scripts/agents/**"],
},
},
};

const changedFiles = [
".github/workflows/labeling.yml",
"scripts/agents/labeling.agent.js",
];

const labels = determineLabelsFromRules(
context,
labelerRules,
changedFiles,
);

expect(labels).toContain("type:feature");
expect(labels).toContain("area:ci");
expect(labels).toContain("area:labels");
expect(labels.filter((label) => label === "area:labels")).toHaveLength(1);
});
});
});
7 changes: 5 additions & 2 deletions scripts/agents/includes/labeler-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@

import fs from "fs";
import yaml from "js-yaml";
import core from "@actions/core";
import * as core from "@actions/core";
import minimatchPackage from "minimatch";

const { minimatch } = minimatchPackage;
const minimatch =
typeof minimatchPackage === "function"
? minimatchPackage
: minimatchPackage.minimatch;

/**
* Loads labeler rules from YAML configuration file
Expand Down
Loading