Migrate to ESMBundler and node 24 (#345)

This commit is contained in:
Kevin Stillhammer
2026-03-28 15:52:59 +00:00
committed by GitHub
parent f611dfc122
commit 0be154b683
22 changed files with 4969 additions and 1045 deletions
+9
View File
@@ -0,0 +1,9 @@
{
"compilerOptions": {
"module": "nodenext",
"moduleResolution": "nodenext",
"target": "es2022",
"types": ["node"]
},
"include": ["check-all-tests-passed-needs.ts"]
}
+3 -2
View File
@@ -27,14 +27,15 @@ jobs:
uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: "20"
node-version-file: .nvmrc
cache: npm
- run: |
npm ci --ignore-scripts
- run: |
npm run all
- name: Check all jobs are in all-tests-passed.needs
run: |
tsc check-all-tests-passed-needs.ts
tsc -p tsconfig.json
node check-all-tests-passed-needs.js
working-directory: .github/scripts
- name: Make sure no changes from linters are detected
+3 -2
View File
@@ -16,11 +16,12 @@ jobs:
persist-credentials: false
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: "20"
node-version-file: .nvmrc
cache: npm
- name: Update known checksums
id: update-known-checksums
run:
node dist/update-known-checksums/index.js
node dist/update-known-checksums/index.cjs
src/download/checksum/known-checksums.ts ${{ secrets.GITHUB_TOKEN }}
- run: npm ci --ignore-scripts && npm run all
- name: Create Pull Request
+1
View File
@@ -0,0 +1 @@
24
+122
View File
@@ -0,0 +1,122 @@
import path from "node:path";
import { fileURLToPath } from "node:url";
import { beforeEach, describe, expect, it, jest } from "@jest/globals";
const debug = jest.fn();
const info = jest.fn();
jest.unstable_mockModule("@actions/core", () => ({
debug,
info,
}));
const { findPyprojectToml } = await import("../../src/utils/pyproject-finder");
const testFilePath = fileURLToPath(import.meta.url);
const testDir = path.dirname(testFilePath);
const repoRoot = path.resolve(testDir, "..", "..");
const fixturesDir = path.join(repoRoot, "__tests__", "fixtures");
describe("findPyprojectToml", () => {
beforeEach(() => {
debug.mockReset();
info.mockReset();
});
describe("when pyproject.toml exists in src directory", () => {
it("should return the exact path", () => {
const result = findPyprojectToml(fixturesDir, repoRoot);
expect(result).toContain("pyproject.toml");
expect(result).toContain("fixtures");
expect(info).toHaveBeenCalled();
});
});
describe("when pyproject.toml exists only in parent directory", () => {
it("should search upwards and find the parent's pyproject.toml", () => {
const subprojectDir = path.join(
fixturesDir,
"parent-config-project",
"subproject",
);
const result = findPyprojectToml(subprojectDir, repoRoot);
expect(result).toBeTruthy();
expect(result).toContain("pyproject.toml");
expect(result).toContain("parent-config-project");
expect(info).toHaveBeenCalled();
});
});
describe("boundary conditions", () => {
it("should stop searching at workspace root and return undefined when not found", () => {
const nodeModulesDir = path.join(repoRoot, "node_modules", "@actions");
const result = findPyprojectToml(nodeModulesDir, repoRoot);
expect(result).toBeUndefined();
expect(info).not.toHaveBeenCalledWith(
expect.stringContaining("Found pyproject.toml"),
);
});
it("should find pyproject.toml when it exists at workspace root", () => {
const parentConfigProjectDir = path.join(
fixturesDir,
"parent-config-project",
);
const subprojectDir = path.join(parentConfigProjectDir, "subproject");
const result = findPyprojectToml(subprojectDir, parentConfigProjectDir);
expect(result).toBeTruthy();
expect(result).toContain("pyproject.toml");
expect(result).toContain("parent-config-project");
});
it("should stop at workspace root even if searching from it", () => {
const result = findPyprojectToml(fixturesDir, fixturesDir);
expect(result).toBeTruthy();
expect(result).toContain("pyproject.toml");
expect(result).toContain("fixtures");
});
});
describe("edge cases", () => {
it("should handle relative paths", () => {
const result = findPyprojectToml("./__tests__/fixtures", ".");
expect(result).toBeTruthy();
expect(result).toContain("pyproject.toml");
});
it("should handle when src equals workspace root", () => {
const result = findPyprojectToml(fixturesDir, fixturesDir);
expect(result).toBeTruthy();
expect(result).toContain("pyproject.toml");
expect(result).toContain("fixtures");
});
it("should log debug messages for each checked path", () => {
const pythonProjectDir = path.join(fixturesDir, "python-project");
findPyprojectToml(pythonProjectDir, repoRoot);
expect(debug).toHaveBeenCalled();
expect(debug.mock.calls.length).toBeGreaterThan(0);
expect(debug.mock.calls[0][0]).toContain("Checking for");
expect(debug.mock.calls[0][0]).toContain("python-project");
});
it("should handle paths with trailing slashes", () => {
const result = findPyprojectToml(`${fixturesDir}/`, repoRoot);
expect(result).toBeTruthy();
expect(result).toContain("pyproject.toml");
});
});
});
@@ -1,77 +1,82 @@
import * as core from "@actions/core";
import { findRuffVersionInSpec } from "./pyproject";
import { beforeEach, describe, expect, it, jest } from "@jest/globals";
jest.mock("@actions/core", () => ({
info: jest.fn(),
warning: jest.fn(),
const info = jest.fn();
const warning = jest.fn();
jest.unstable_mockModule("@actions/core", () => ({
info,
warning,
}));
const { findRuffVersionInSpec } = await import("../../src/utils/pyproject");
describe("findRuffVersionInSpec", () => {
beforeEach(() => {
jest.clearAllMocks();
info.mockReset();
warning.mockReset();
});
describe("ruff dependency strings", () => {
it("should extract version from 'ruff==0.9.3'", () => {
const result = findRuffVersionInSpec("ruff==0.9.3");
expect(result).toBe("0.9.3");
expect(core.info).toHaveBeenCalledWith(
expect(info).toHaveBeenCalledWith(
"Found ruff version in requirements file: 0.9.3",
);
expect(core.warning).not.toHaveBeenCalled();
expect(warning).not.toHaveBeenCalled();
});
it("should extract version from 'ruff>=0.14'", () => {
const result = findRuffVersionInSpec("ruff>=0.14");
expect(result).toBe(">=0.14");
expect(core.warning).not.toHaveBeenCalled();
expect(warning).not.toHaveBeenCalled();
});
it("should extract version from 'ruff ~=1.0.0'", () => {
const result = findRuffVersionInSpec("ruff ~=1.0.0");
expect(result).toBe("~=1.0.0");
expect(core.warning).not.toHaveBeenCalled();
expect(warning).not.toHaveBeenCalled();
});
it("should extract version from 'ruff>=0.14,<1.0'", () => {
const result = findRuffVersionInSpec("ruff>=0.14,<1.0");
expect(result).toBe(">=0.14,<1.0");
expect(core.warning).not.toHaveBeenCalled();
expect(warning).not.toHaveBeenCalled();
});
it("should extract version from 'ruff>=0.14,<2.0,!=1.5.0'", () => {
const result = findRuffVersionInSpec("ruff>=0.14,<2.0,!=1.5.0");
expect(result).toBe(">=0.14,<2.0,!=1.5.0");
expect(core.warning).not.toHaveBeenCalled();
expect(warning).not.toHaveBeenCalled();
});
it("should return undefined for non-ruff dependency 'another-dep 0.1.6'", () => {
const result = findRuffVersionInSpec("another-dep 0.1.6");
expect(result).toBeUndefined();
expect(core.info).not.toHaveBeenCalled();
expect(core.warning).not.toHaveBeenCalled();
expect(info).not.toHaveBeenCalled();
expect(warning).not.toHaveBeenCalled();
});
it("should return undefined for non-ruff dependency 'another-dep==0.1.6'", () => {
const result = findRuffVersionInSpec("another-dep==0.1.6");
expect(result).toBeUndefined();
expect(core.info).not.toHaveBeenCalled();
expect(core.warning).not.toHaveBeenCalled();
expect(info).not.toHaveBeenCalled();
expect(warning).not.toHaveBeenCalled();
});
it("should strip trailing backslash", () => {
const result = findRuffVersionInSpec("ruff==0.9.3 \\");
expect(result).toBe("0.9.3");
expect(core.info).toHaveBeenCalledWith(
expect(info).toHaveBeenCalledWith(
"Found ruff version in requirements file: 0.9.3",
);
expect(core.warning).not.toHaveBeenCalled();
expect(warning).not.toHaveBeenCalled();
});
it("should strip trailing backslash with whitespace", () => {
const result = findRuffVersionInSpec(" ruff==0.9.3 \\ ");
expect(result).toBe("0.9.3");
expect(core.warning).not.toHaveBeenCalled();
expect(warning).not.toHaveBeenCalled();
});
});
@@ -81,10 +86,10 @@ describe("findRuffVersionInSpec", () => {
'ruff>=0.14 ; python_version >= "3.11"',
);
expect(result).toBe(">=0.14");
expect(core.info).toHaveBeenCalledWith(
expect(info).toHaveBeenCalledWith(
"Found ruff version in requirements file: >=0.14",
);
expect(core.warning).toHaveBeenCalledWith(
expect(warning).toHaveBeenCalledWith(
"Environment markers are ignored. ruff is a standalone tool that works independently of Python version.",
);
});
@@ -94,7 +99,7 @@ describe("findRuffVersionInSpec", () => {
"ruff==0.9.3 ; sys_platform == 'linux'",
);
expect(result).toBe("0.9.3");
expect(core.warning).toHaveBeenCalledWith(
expect(warning).toHaveBeenCalledWith(
"Environment markers are ignored. ruff is a standalone tool that works independently of Python version.",
);
});
@@ -104,7 +109,7 @@ describe("findRuffVersionInSpec", () => {
'ruff>=0.14 ; python_version >= "3.11" and sys_platform == "linux"',
);
expect(result).toBe(">=0.14");
expect(core.warning).toHaveBeenCalledWith(
expect(warning).toHaveBeenCalledWith(
"Environment markers are ignored. ruff is a standalone tool that works independently of Python version.",
);
});
@@ -114,7 +119,7 @@ describe("findRuffVersionInSpec", () => {
'ruff>=0.14,<1.0 ; python_version >= "3.11"',
);
expect(result).toBe(">=0.14,<1.0");
expect(core.warning).toHaveBeenCalledWith(
expect(warning).toHaveBeenCalledWith(
"Environment markers are ignored. ruff is a standalone tool that works independently of Python version.",
);
});
@@ -124,7 +129,7 @@ describe("findRuffVersionInSpec", () => {
it("should handle whitespace", () => {
const result = findRuffVersionInSpec(" ruff >=0.14 ");
expect(result).toBe(">=0.14");
expect(core.warning).not.toHaveBeenCalled();
expect(warning).not.toHaveBeenCalled();
});
it("should handle whitespace with environment markers", () => {
@@ -132,28 +137,28 @@ describe("findRuffVersionInSpec", () => {
" ruff >=0.14 ; python_version >= '3.11' ",
);
expect(result).toBe(">=0.14");
expect(core.warning).toHaveBeenCalled();
expect(warning).toHaveBeenCalled();
});
it("should return undefined for empty string", () => {
const result = findRuffVersionInSpec("");
expect(result).toBeUndefined();
expect(core.info).not.toHaveBeenCalled();
expect(core.warning).not.toHaveBeenCalled();
expect(info).not.toHaveBeenCalled();
expect(warning).not.toHaveBeenCalled();
});
it("should return undefined for whitespace only", () => {
const result = findRuffVersionInSpec(" ");
expect(result).toBeUndefined();
expect(core.info).not.toHaveBeenCalled();
expect(core.warning).not.toHaveBeenCalled();
expect(info).not.toHaveBeenCalled();
expect(warning).not.toHaveBeenCalled();
});
it("should return undefined for just semicolon", () => {
const result = findRuffVersionInSpec(";");
expect(result).toBeUndefined();
expect(core.info).not.toHaveBeenCalled();
expect(core.warning).not.toHaveBeenCalled();
expect(info).not.toHaveBeenCalled();
expect(warning).not.toHaveBeenCalled();
});
it("should handle exact example from issue #256", () => {
@@ -161,10 +166,10 @@ describe("findRuffVersionInSpec", () => {
'ruff>=0.14 ; python_version >= "3.11"',
);
expect(result).toBe(">=0.14");
expect(core.info).toHaveBeenCalledWith(
expect(info).toHaveBeenCalledWith(
"Found ruff version in requirements file: >=0.14",
);
expect(core.warning).toHaveBeenCalledWith(
expect(warning).toHaveBeenCalledWith(
"Environment markers are ignored. ruff is a standalone tool that works independently of Python version.",
);
});
@@ -174,7 +179,7 @@ describe("findRuffVersionInSpec", () => {
"ruff>=0.14 ; python_version >= '3.11'",
);
expect(result).toBe(">=0.14");
expect(core.warning).toHaveBeenCalled();
expect(warning).toHaveBeenCalled();
});
it("should handle double-quoted environment markers", () => {
@@ -182,7 +187,7 @@ describe("findRuffVersionInSpec", () => {
'ruff>=0.14 ; python_version >= "3.11"',
);
expect(result).toBe(">=0.14");
expect(core.warning).toHaveBeenCalled();
expect(warning).toHaveBeenCalled();
});
});
});
+2 -2
View File
@@ -30,8 +30,8 @@ outputs:
ruff-version:
description: "The installed ruff version. Useful when using latest."
runs:
using: "node20"
main: "dist/ruff-action/index.js"
using: "node24"
main: "dist/ruff-action/index.cjs"
branding:
icon: "code"
color: "black"
+1 -1
View File
@@ -1,5 +1,5 @@
{
"$schema": "https://biomejs.dev/schemas/2.3.2/schema.json",
"$schema": "https://biomejs.dev/schemas/2.4.9/schema.json",
"assist": {
"actions": {
"source": {
Generated Vendored
BIN
View File
Binary file not shown.
Generated Vendored
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
-12
View File
@@ -1,12 +0,0 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
collectCoverageFrom: ["src/**/*.ts", "!src/**/*.d.ts"],
moduleFileExtensions: ["ts", "js"],
preset: "ts-jest",
roots: ["<rootDir>/src"],
testEnvironment: "node",
testMatch: ["**/*.test.ts"],
transform: {
"^.+\\.ts$": "ts-jest",
},
};
+12
View File
@@ -0,0 +1,12 @@
import { createDefaultEsmPreset } from "ts-jest";
const preset = createDefaultEsmPreset();
/** @type {import('jest').Config} */
export default {
...preset,
collectCoverageFrom: ["src/**/*.ts", "!src/**/*.d.ts"],
moduleFileExtensions: ["ts", "js", "mjs"],
testEnvironment: "node",
testMatch: ["<rootDir>/__tests__/**/*.test.ts"],
};
+4690 -745
View File
File diff suppressed because it is too large Load Diff
+18 -16
View File
@@ -2,16 +2,18 @@
"name": "ruff-action",
"version": "1.0.0",
"private": true,
"type": "module",
"description": "A GitHub Action to run Ruff, an extremely fast Python linter and code formatter.",
"main": "dist/ruff-action/index.js",
"main": "dist/ruff-action/index.cjs",
"scripts": {
"build": "tsc",
"build": "tsc --noEmit",
"check": "biome check --write",
"package": "ncc build -o dist/ruff-action src/ruff-action.ts && ncc build -o dist/update-known-checksums src/update-known-checksums.ts",
"package": "node scripts/build-dist.mjs",
"act": "act pull_request -W .github/workflows/test.yml --container-architecture linux/amd64 -s GITHUB_TOKEN=\"$(gh auth token)\"",
"update-known-checksums": "RUNNER_TEMP=known_checksums node dist/update-known-checksums/index.js src/download/checksum/known-checksums.ts \"$(gh auth token)\"",
"test": "jest",
"all": "npm ci --ignore-scripts && npm run build && npm run check && npm run test && npm run package"
"update-known-checksums": "RUNNER_TEMP=known_checksums node dist/update-known-checksums/index.cjs src/download/checksum/known-checksums.ts \"$(gh auth token)\"",
"test:unit": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js",
"test": "npm run build && npm run test:unit",
"all": "npm run build && npm run check && npm run package && npm run test:unit"
},
"repository": {
"type": "git",
@@ -26,9 +28,9 @@
"author": "@eifinger",
"license": "Apache-2.0",
"dependencies": {
"@actions/core": "^1.11.1",
"@actions/exec": "^1.1.1",
"@actions/tool-cache": "^2.0.2",
"@actions/core": "^3.0.0",
"@actions/exec": "^3.0.0",
"@actions/tool-cache": "^4.0.0",
"@octokit/core": "^7.0.3",
"@octokit/plugin-paginate-rest": "^13.1.1",
"@octokit/plugin-rest-endpoint-methods": "^16.0.0",
@@ -36,15 +38,15 @@
"smol-toml": "^1.6.0"
},
"devDependencies": {
"@biomejs/biome": "2.3.2",
"@biomejs/biome": "^2.4.7",
"@types/jest": "^29.5.14",
"@types/js-yaml": "^4.0.9",
"@types/node": "^24.10.9",
"@types/node": "^25.5.0",
"@types/semver": "^7.7.1",
"@vercel/ncc": "^0.38.3",
"jest": "^29.7.0",
"js-yaml": "^4.1.0",
"ts-jest": "^29.2.5",
"typescript": "^5.9.2"
"esbuild": "^0.27.4",
"jest": "^30.3.0",
"js-yaml": "^4.1.1",
"ts-jest": "^29.4.6",
"typescript": "^5.9.3"
}
}
+41
View File
@@ -0,0 +1,41 @@
import { mkdir, rm } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { build } from "esbuild";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const repoRoot = path.resolve(__dirname, "..");
const builds = [
{
entryPoint: path.join(repoRoot, "src", "ruff-action.ts"),
outfile: path.join(repoRoot, "dist", "ruff-action", "index.cjs"),
staleOutfile: path.join(repoRoot, "dist", "ruff-action", "index.js"),
},
{
entryPoint: path.join(repoRoot, "src", "update-known-checksums.ts"),
outfile: path.join(repoRoot, "dist", "update-known-checksums", "index.cjs"),
staleOutfile: path.join(
repoRoot,
"dist",
"update-known-checksums",
"index.js",
),
},
];
await Promise.all(
builds.map(async ({ entryPoint, outfile, staleOutfile }) => {
await rm(staleOutfile, { force: true });
await mkdir(path.dirname(outfile), { recursive: true });
await build({
bundle: true,
entryPoints: [entryPoint],
format: "cjs",
outfile,
platform: "node",
target: "node24",
});
}),
);
+7 -6
View File
@@ -136,16 +136,17 @@ function setOutputFormat() {
}
function addMatchers(): void {
const matchersPath = path.join(
__dirname,
`..${path.sep}..`,
".github",
"matchers",
);
const actionRoot = getActionRoot();
const matchersPath = path.join(actionRoot, ".github", "matchers");
core.info(`##[add-matcher]${path.join(matchersPath, "check.json")}`);
core.info(`##[add-matcher]${path.join(matchersPath, "format.json")}`);
}
function getActionRoot(): string {
const entrypoint = process.argv[1] ?? process.cwd();
return path.resolve(path.dirname(entrypoint), "..", "..");
}
async function runRuff(
ruffExecutablePath: string,
args: string[],
+2 -2
View File
@@ -10,9 +10,9 @@ const PaginatingOctokit = Octokit.plugin(paginateRest, restEndpointMethods);
async function run(): Promise<void> {
const checksumFilePath = process.argv.slice(2)[0];
const github_token = process.argv.slice(2)[1];
const githubToken = process.argv.slice(2)[1];
const octokit = new PaginatingOctokit({ auth: github_token });
const octokit = new PaginatingOctokit({ auth: githubToken });
const response = await octokit.paginate(octokit.rest.repos.listReleases, {
owner: OWNER,
-183
View File
@@ -1,183 +0,0 @@
import * as path from "node:path";
import * as core from "@actions/core";
import { findPyprojectToml } from "./pyproject-finder";
jest.mock("@actions/core", () => ({
debug: jest.fn(),
info: jest.fn(),
}));
describe("findPyprojectToml", () => {
beforeEach(() => {
jest.clearAllMocks();
});
describe("when pyproject.toml exists in src directory", () => {
it("should return the exact path", () => {
const fixturesDir = path.join(
__dirname,
"..",
"..",
"__tests__",
"fixtures",
);
const workspaceRoot = path.join(__dirname, "..", "..");
const result = findPyprojectToml(fixturesDir, workspaceRoot);
expect(result).toContain("pyproject.toml");
expect(result).toContain("fixtures");
expect(core.info).toHaveBeenCalled();
});
});
describe("when pyproject.toml exists only in parent directory", () => {
it("should search upwards and find the parent's pyproject.toml", () => {
// subproject doesn't have a pyproject.toml, but its parent (parent-config-project) does
const subprojectDir = path.join(
__dirname,
"..",
"..",
"__tests__",
"fixtures",
"parent-config-project",
"subproject",
);
const workspaceRoot = path.join(__dirname, "..", "..");
const result = findPyprojectToml(subprojectDir, workspaceRoot);
expect(result).toBeTruthy();
expect(result).toContain("pyproject.toml");
expect(result).toContain("parent-config-project");
expect(core.info).toHaveBeenCalled();
});
});
describe("boundary conditions", () => {
it("should stop searching at workspace root and return undefined when not found", () => {
// Create a path that won't have pyproject.toml above it
const nodeModulesDir = path.join(
__dirname,
"..",
"..",
"node_modules",
"@actions",
);
const workspaceRoot = path.join(__dirname, "..", "..");
const result = findPyprojectToml(nodeModulesDir, workspaceRoot);
// Should return undefined since there's no pyproject.toml in the search path
expect(result).toBeUndefined();
expect(core.info).not.toHaveBeenCalledWith(
expect.stringContaining("Found pyproject.toml"),
);
});
it("should find pyproject.toml when it exists at workspace root", () => {
// Use parent-config-project as the "workspace root" for this test
// Start from subproject (which has no pyproject.toml) to search up to workspace root
const subprojectDir = path.join(
__dirname,
"..",
"..",
"__tests__",
"fixtures",
"parent-config-project",
"subproject",
);
const workspaceRoot = path.join(
__dirname,
"..",
"..",
"__tests__",
"fixtures",
"parent-config-project",
);
const result = findPyprojectToml(subprojectDir, workspaceRoot);
expect(result).toBeTruthy();
expect(result).toContain("pyproject.toml");
expect(result).toContain("parent-config-project");
});
it("should stop at workspace root even if searching from it", () => {
const workspaceRoot = path.join(
__dirname,
"..",
"..",
"__tests__",
"fixtures",
);
const result = findPyprojectToml(workspaceRoot, workspaceRoot);
// Should find pyproject.toml at workspace root
expect(result).toBeTruthy();
expect(result).toContain("pyproject.toml");
expect(result).toContain("fixtures");
});
});
describe("edge cases", () => {
it("should handle relative paths", () => {
const srcDir = "./__tests__/fixtures";
const workspaceRoot = ".";
const result = findPyprojectToml(srcDir, workspaceRoot);
// Should work with relative paths
expect(result).toBeTruthy();
expect(result).toContain("pyproject.toml");
});
it("should handle when src equals workspace root", () => {
const workspaceRoot = path.join(
__dirname,
"..",
"..",
"__tests__",
"fixtures",
);
const result = findPyprojectToml(workspaceRoot, workspaceRoot);
expect(result).toBeTruthy();
expect(result).toContain("pyproject.toml");
expect(result).toContain("fixtures");
});
it("should log debug messages for each checked path", () => {
const pythonProjectDir = path.join(
__dirname,
"..",
"..",
"__tests__",
"fixtures",
"python-project",
);
const workspaceRoot = path.join(__dirname, "..", "..");
findPyprojectToml(pythonProjectDir, workspaceRoot);
expect(core.debug).toHaveBeenCalled();
const debugCalls = (core.debug as jest.Mock).mock.calls;
expect(debugCalls.length).toBeGreaterThan(0);
// First debug call should be for the starting directory
expect(debugCalls[0][0]).toContain("Checking for");
expect(debugCalls[0][0]).toContain("python-project");
});
it("should handle paths with trailing slashes", () => {
const fixturesDir = `${path.join(__dirname, "..", "..", "__tests__", "fixtures")}/`;
const workspaceRoot = path.join(__dirname, "..", "..");
const result = findPyprojectToml(fixturesDir, workspaceRoot);
expect(result).toBeTruthy();
expect(result).toContain("pyproject.toml");
});
});
});
+9 -30
View File
@@ -26,30 +26,20 @@ export function findPyprojectToml(
core.info(`Found pyproject.toml at ${pyprojectPath}`);
return pyprojectPath;
}
// Check if we've reached the workspace root
if (currentDir === resolvedWorkspaceRoot) {
// If we're at workspace root and didn't find it, stop searching
break;
return undefined;
}
// Move up to parent directory
const parentDir = path.dirname(currentDir);
// If parent is the same as current, we've reached the filesystem root
if (parentDir === currentDir) {
break;
if (
parentDir === currentDir ||
!isPathWithinWorkspace(parentDir, resolvedWorkspaceRoot)
) {
return undefined;
}
currentDir = parentDir;
// If we've gone past the workspace root, stop searching
if (isPathWithinWorkspace(currentDir, resolvedWorkspaceRoot) === false) {
break;
}
}
return undefined;
}
/**
@@ -62,18 +52,7 @@ export function findPyprojectToml(
function isPathWithinWorkspace(
checkPath: string,
workspaceRoot: string,
): boolean | undefined {
try {
const checkPathResolved = path.resolve(checkPath);
const workspaceRootResolved = path.resolve(workspaceRoot);
// Check if checkPath starts with workspaceRoot (case-insensitive on Windows)
const relativePath = path.relative(
workspaceRootResolved,
checkPathResolved,
);
return !relativePath.startsWith("..") && !path.isAbsolute(relativePath);
} catch {
return undefined;
}
): boolean {
const relativePath = path.relative(workspaceRoot, checkPath);
return !relativePath.startsWith("..") && !path.isAbsolute(relativePath);
}
+8 -8
View File
@@ -1,12 +1,12 @@
{
"compilerOptions": {
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
"noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
"outDir": "./lib" /* Redirect output structure to the directory. */,
"rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
"strict": true /* Enable all strict type-checking options. */,
"target": "ES2022" /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"esModuleInterop": true,
"isolatedModules": true,
"module": "esnext",
"moduleResolution": "bundler",
"noImplicitAny": true,
"strict": true,
"target": "ES2022"
},
"exclude": ["node_modules", "**/*.test.ts"]
"include": ["src/**/*.ts"]
}