-
Notifications
You must be signed in to change notification settings - Fork 1
fix(labeling): harden labeler rule matching and add tests #430
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,97 @@ | ||||||||||||||||||||||||||||
| const { | ||||||||||||||||||||||||||||
| matchesBranchPattern, | ||||||||||||||||||||||||||||
| matchesFilePatterns, | ||||||||||||||||||||||||||||
| determineLabelsFromRules, | ||||||||||||||||||||||||||||
| } = require("../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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The test for
Suggested change
|
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| 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); | ||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since
labeler-utils.jsis an ES module (usingimport/exportsyntax), using CommonJSrequireto load it will fail at runtime in standard Node.js environments withERR_REQUIRE_ESM. To ensure compatibility and consistency with the rest of the codebase, use ES moduleimportsyntax instead.