mirror of
https://github.com/astral-sh/ruff-action.git
synced 2026-05-19 15:30:14 +02:00
Migrate to ESMBundler and node 24 (#345)
This commit is contained in:
committed by
GitHub
parent
f611dfc122
commit
0be154b683
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "nodenext",
|
||||||
|
"moduleResolution": "nodenext",
|
||||||
|
"target": "es2022",
|
||||||
|
"types": ["node"]
|
||||||
|
},
|
||||||
|
"include": ["check-all-tests-passed-needs.ts"]
|
||||||
|
}
|
||||||
@@ -27,14 +27,15 @@ jobs:
|
|||||||
uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2
|
uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2
|
||||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version-file: .nvmrc
|
||||||
|
cache: npm
|
||||||
- run: |
|
- run: |
|
||||||
npm ci --ignore-scripts
|
npm ci --ignore-scripts
|
||||||
- run: |
|
- run: |
|
||||||
npm run all
|
npm run all
|
||||||
- name: Check all jobs are in all-tests-passed.needs
|
- name: Check all jobs are in all-tests-passed.needs
|
||||||
run: |
|
run: |
|
||||||
tsc check-all-tests-passed-needs.ts
|
tsc -p tsconfig.json
|
||||||
node check-all-tests-passed-needs.js
|
node check-all-tests-passed-needs.js
|
||||||
working-directory: .github/scripts
|
working-directory: .github/scripts
|
||||||
- name: Make sure no changes from linters are detected
|
- name: Make sure no changes from linters are detected
|
||||||
|
|||||||
@@ -16,11 +16,12 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version-file: .nvmrc
|
||||||
|
cache: npm
|
||||||
- name: Update known checksums
|
- name: Update known checksums
|
||||||
id: update-known-checksums
|
id: update-known-checksums
|
||||||
run:
|
run:
|
||||||
node dist/update-known-checksums/index.js
|
node dist/update-known-checksums/index.cjs
|
||||||
src/download/checksum/known-checksums.ts ${{ secrets.GITHUB_TOKEN }}
|
src/download/checksum/known-checksums.ts ${{ secrets.GITHUB_TOKEN }}
|
||||||
- run: npm ci --ignore-scripts && npm run all
|
- run: npm ci --ignore-scripts && npm run all
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
|
|||||||
@@ -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 { beforeEach, describe, expect, it, jest } from "@jest/globals";
|
||||||
import { findRuffVersionInSpec } from "./pyproject";
|
|
||||||
|
|
||||||
jest.mock("@actions/core", () => ({
|
const info = jest.fn();
|
||||||
info: jest.fn(),
|
const warning = jest.fn();
|
||||||
warning: jest.fn(),
|
|
||||||
|
jest.unstable_mockModule("@actions/core", () => ({
|
||||||
|
info,
|
||||||
|
warning,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const { findRuffVersionInSpec } = await import("../../src/utils/pyproject");
|
||||||
|
|
||||||
describe("findRuffVersionInSpec", () => {
|
describe("findRuffVersionInSpec", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
info.mockReset();
|
||||||
|
warning.mockReset();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("ruff dependency strings", () => {
|
describe("ruff dependency strings", () => {
|
||||||
it("should extract version from 'ruff==0.9.3'", () => {
|
it("should extract version from 'ruff==0.9.3'", () => {
|
||||||
const result = findRuffVersionInSpec("ruff==0.9.3");
|
const result = findRuffVersionInSpec("ruff==0.9.3");
|
||||||
expect(result).toBe("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",
|
"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'", () => {
|
it("should extract version from 'ruff>=0.14'", () => {
|
||||||
const result = findRuffVersionInSpec("ruff>=0.14");
|
const result = findRuffVersionInSpec("ruff>=0.14");
|
||||||
expect(result).toBe(">=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'", () => {
|
it("should extract version from 'ruff ~=1.0.0'", () => {
|
||||||
const result = findRuffVersionInSpec("ruff ~=1.0.0");
|
const result = findRuffVersionInSpec("ruff ~=1.0.0");
|
||||||
expect(result).toBe("~=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'", () => {
|
it("should extract version from 'ruff>=0.14,<1.0'", () => {
|
||||||
const result = findRuffVersionInSpec("ruff>=0.14,<1.0");
|
const result = findRuffVersionInSpec("ruff>=0.14,<1.0");
|
||||||
expect(result).toBe(">=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'", () => {
|
it("should extract version from 'ruff>=0.14,<2.0,!=1.5.0'", () => {
|
||||||
const result = findRuffVersionInSpec("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(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'", () => {
|
it("should return undefined for non-ruff dependency 'another-dep 0.1.6'", () => {
|
||||||
const result = findRuffVersionInSpec("another-dep 0.1.6");
|
const result = findRuffVersionInSpec("another-dep 0.1.6");
|
||||||
expect(result).toBeUndefined();
|
expect(result).toBeUndefined();
|
||||||
expect(core.info).not.toHaveBeenCalled();
|
expect(info).not.toHaveBeenCalled();
|
||||||
expect(core.warning).not.toHaveBeenCalled();
|
expect(warning).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return undefined for non-ruff dependency 'another-dep==0.1.6'", () => {
|
it("should return undefined for non-ruff dependency 'another-dep==0.1.6'", () => {
|
||||||
const result = findRuffVersionInSpec("another-dep==0.1.6");
|
const result = findRuffVersionInSpec("another-dep==0.1.6");
|
||||||
expect(result).toBeUndefined();
|
expect(result).toBeUndefined();
|
||||||
expect(core.info).not.toHaveBeenCalled();
|
expect(info).not.toHaveBeenCalled();
|
||||||
expect(core.warning).not.toHaveBeenCalled();
|
expect(warning).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should strip trailing backslash", () => {
|
it("should strip trailing backslash", () => {
|
||||||
const result = findRuffVersionInSpec("ruff==0.9.3 \\");
|
const result = findRuffVersionInSpec("ruff==0.9.3 \\");
|
||||||
expect(result).toBe("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",
|
"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", () => {
|
it("should strip trailing backslash with whitespace", () => {
|
||||||
const result = findRuffVersionInSpec(" ruff==0.9.3 \\ ");
|
const result = findRuffVersionInSpec(" ruff==0.9.3 \\ ");
|
||||||
expect(result).toBe("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"',
|
'ruff>=0.14 ; python_version >= "3.11"',
|
||||||
);
|
);
|
||||||
expect(result).toBe(">=0.14");
|
expect(result).toBe(">=0.14");
|
||||||
expect(core.info).toHaveBeenCalledWith(
|
expect(info).toHaveBeenCalledWith(
|
||||||
"Found ruff version in requirements file: >=0.14",
|
"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.",
|
"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'",
|
"ruff==0.9.3 ; sys_platform == 'linux'",
|
||||||
);
|
);
|
||||||
expect(result).toBe("0.9.3");
|
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.",
|
"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"',
|
'ruff>=0.14 ; python_version >= "3.11" and sys_platform == "linux"',
|
||||||
);
|
);
|
||||||
expect(result).toBe(">=0.14");
|
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.",
|
"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"',
|
'ruff>=0.14,<1.0 ; python_version >= "3.11"',
|
||||||
);
|
);
|
||||||
expect(result).toBe(">=0.14,<1.0");
|
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.",
|
"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", () => {
|
it("should handle whitespace", () => {
|
||||||
const result = findRuffVersionInSpec(" ruff >=0.14 ");
|
const result = findRuffVersionInSpec(" ruff >=0.14 ");
|
||||||
expect(result).toBe(">=0.14");
|
expect(result).toBe(">=0.14");
|
||||||
expect(core.warning).not.toHaveBeenCalled();
|
expect(warning).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should handle whitespace with environment markers", () => {
|
it("should handle whitespace with environment markers", () => {
|
||||||
@@ -132,28 +137,28 @@ describe("findRuffVersionInSpec", () => {
|
|||||||
" ruff >=0.14 ; python_version >= '3.11' ",
|
" ruff >=0.14 ; python_version >= '3.11' ",
|
||||||
);
|
);
|
||||||
expect(result).toBe(">=0.14");
|
expect(result).toBe(">=0.14");
|
||||||
expect(core.warning).toHaveBeenCalled();
|
expect(warning).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return undefined for empty string", () => {
|
it("should return undefined for empty string", () => {
|
||||||
const result = findRuffVersionInSpec("");
|
const result = findRuffVersionInSpec("");
|
||||||
expect(result).toBeUndefined();
|
expect(result).toBeUndefined();
|
||||||
expect(core.info).not.toHaveBeenCalled();
|
expect(info).not.toHaveBeenCalled();
|
||||||
expect(core.warning).not.toHaveBeenCalled();
|
expect(warning).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return undefined for whitespace only", () => {
|
it("should return undefined for whitespace only", () => {
|
||||||
const result = findRuffVersionInSpec(" ");
|
const result = findRuffVersionInSpec(" ");
|
||||||
expect(result).toBeUndefined();
|
expect(result).toBeUndefined();
|
||||||
expect(core.info).not.toHaveBeenCalled();
|
expect(info).not.toHaveBeenCalled();
|
||||||
expect(core.warning).not.toHaveBeenCalled();
|
expect(warning).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return undefined for just semicolon", () => {
|
it("should return undefined for just semicolon", () => {
|
||||||
const result = findRuffVersionInSpec(";");
|
const result = findRuffVersionInSpec(";");
|
||||||
expect(result).toBeUndefined();
|
expect(result).toBeUndefined();
|
||||||
expect(core.info).not.toHaveBeenCalled();
|
expect(info).not.toHaveBeenCalled();
|
||||||
expect(core.warning).not.toHaveBeenCalled();
|
expect(warning).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should handle exact example from issue #256", () => {
|
it("should handle exact example from issue #256", () => {
|
||||||
@@ -161,10 +166,10 @@ describe("findRuffVersionInSpec", () => {
|
|||||||
'ruff>=0.14 ; python_version >= "3.11"',
|
'ruff>=0.14 ; python_version >= "3.11"',
|
||||||
);
|
);
|
||||||
expect(result).toBe(">=0.14");
|
expect(result).toBe(">=0.14");
|
||||||
expect(core.info).toHaveBeenCalledWith(
|
expect(info).toHaveBeenCalledWith(
|
||||||
"Found ruff version in requirements file: >=0.14",
|
"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.",
|
"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'",
|
"ruff>=0.14 ; python_version >= '3.11'",
|
||||||
);
|
);
|
||||||
expect(result).toBe(">=0.14");
|
expect(result).toBe(">=0.14");
|
||||||
expect(core.warning).toHaveBeenCalled();
|
expect(warning).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should handle double-quoted environment markers", () => {
|
it("should handle double-quoted environment markers", () => {
|
||||||
@@ -182,7 +187,7 @@ describe("findRuffVersionInSpec", () => {
|
|||||||
'ruff>=0.14 ; python_version >= "3.11"',
|
'ruff>=0.14 ; python_version >= "3.11"',
|
||||||
);
|
);
|
||||||
expect(result).toBe(">=0.14");
|
expect(result).toBe(">=0.14");
|
||||||
expect(core.warning).toHaveBeenCalled();
|
expect(warning).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
+2
-2
@@ -30,8 +30,8 @@ outputs:
|
|||||||
ruff-version:
|
ruff-version:
|
||||||
description: "The installed ruff version. Useful when using latest."
|
description: "The installed ruff version. Useful when using latest."
|
||||||
runs:
|
runs:
|
||||||
using: "node20"
|
using: "node24"
|
||||||
main: "dist/ruff-action/index.js"
|
main: "dist/ruff-action/index.cjs"
|
||||||
branding:
|
branding:
|
||||||
icon: "code"
|
icon: "code"
|
||||||
color: "black"
|
color: "black"
|
||||||
|
|||||||
+1
-1
@@ -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": {
|
"assist": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"source": {
|
"source": {
|
||||||
|
|||||||
+32322
File diff suppressed because one or more lines are too long
-39550
File diff suppressed because one or more lines are too long
+29510
File diff suppressed because one or more lines are too long
-37282
File diff suppressed because one or more lines are too long
@@ -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",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -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"],
|
||||||
|
};
|
||||||
Generated
+4690
-745
File diff suppressed because it is too large
Load Diff
+18
-16
@@ -2,16 +2,18 @@
|
|||||||
"name": "ruff-action",
|
"name": "ruff-action",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
"description": "A GitHub Action to run Ruff, an extremely fast Python linter and code formatter.",
|
"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": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc --noEmit",
|
||||||
"check": "biome check --write",
|
"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)\"",
|
"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)\"",
|
"update-known-checksums": "RUNNER_TEMP=known_checksums node dist/update-known-checksums/index.cjs src/download/checksum/known-checksums.ts \"$(gh auth token)\"",
|
||||||
"test": "jest",
|
"test:unit": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js",
|
||||||
"all": "npm ci --ignore-scripts && npm run build && npm run check && npm run test && npm run package"
|
"test": "npm run build && npm run test:unit",
|
||||||
|
"all": "npm run build && npm run check && npm run package && npm run test:unit"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -26,9 +28,9 @@
|
|||||||
"author": "@eifinger",
|
"author": "@eifinger",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.11.1",
|
"@actions/core": "^3.0.0",
|
||||||
"@actions/exec": "^1.1.1",
|
"@actions/exec": "^3.0.0",
|
||||||
"@actions/tool-cache": "^2.0.2",
|
"@actions/tool-cache": "^4.0.0",
|
||||||
"@octokit/core": "^7.0.3",
|
"@octokit/core": "^7.0.3",
|
||||||
"@octokit/plugin-paginate-rest": "^13.1.1",
|
"@octokit/plugin-paginate-rest": "^13.1.1",
|
||||||
"@octokit/plugin-rest-endpoint-methods": "^16.0.0",
|
"@octokit/plugin-rest-endpoint-methods": "^16.0.0",
|
||||||
@@ -36,15 +38,15 @@
|
|||||||
"smol-toml": "^1.6.0"
|
"smol-toml": "^1.6.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "2.3.2",
|
"@biomejs/biome": "^2.4.7",
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^29.5.14",
|
||||||
"@types/js-yaml": "^4.0.9",
|
"@types/js-yaml": "^4.0.9",
|
||||||
"@types/node": "^24.10.9",
|
"@types/node": "^25.5.0",
|
||||||
"@types/semver": "^7.7.1",
|
"@types/semver": "^7.7.1",
|
||||||
"@vercel/ncc": "^0.38.3",
|
"esbuild": "^0.27.4",
|
||||||
"jest": "^29.7.0",
|
"jest": "^30.3.0",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.1",
|
||||||
"ts-jest": "^29.2.5",
|
"ts-jest": "^29.4.6",
|
||||||
"typescript": "^5.9.2"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -136,16 +136,17 @@ function setOutputFormat() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addMatchers(): void {
|
function addMatchers(): void {
|
||||||
const matchersPath = path.join(
|
const actionRoot = getActionRoot();
|
||||||
__dirname,
|
const matchersPath = path.join(actionRoot, ".github", "matchers");
|
||||||
`..${path.sep}..`,
|
|
||||||
".github",
|
|
||||||
"matchers",
|
|
||||||
);
|
|
||||||
core.info(`##[add-matcher]${path.join(matchersPath, "check.json")}`);
|
core.info(`##[add-matcher]${path.join(matchersPath, "check.json")}`);
|
||||||
core.info(`##[add-matcher]${path.join(matchersPath, "format.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(
|
async function runRuff(
|
||||||
ruffExecutablePath: string,
|
ruffExecutablePath: string,
|
||||||
args: string[],
|
args: string[],
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ const PaginatingOctokit = Octokit.plugin(paginateRest, restEndpointMethods);
|
|||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
const checksumFilePath = process.argv.slice(2)[0];
|
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, {
|
const response = await octokit.paginate(octokit.rest.repos.listReleases, {
|
||||||
owner: OWNER,
|
owner: OWNER,
|
||||||
|
|||||||
@@ -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");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -26,30 +26,20 @@ export function findPyprojectToml(
|
|||||||
core.info(`Found pyproject.toml at ${pyprojectPath}`);
|
core.info(`Found pyproject.toml at ${pyprojectPath}`);
|
||||||
return pyprojectPath;
|
return pyprojectPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we've reached the workspace root
|
|
||||||
if (currentDir === resolvedWorkspaceRoot) {
|
if (currentDir === resolvedWorkspaceRoot) {
|
||||||
// If we're at workspace root and didn't find it, stop searching
|
return undefined;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move up to parent directory
|
|
||||||
const parentDir = path.dirname(currentDir);
|
const parentDir = path.dirname(currentDir);
|
||||||
|
if (
|
||||||
// If parent is the same as current, we've reached the filesystem root
|
parentDir === currentDir ||
|
||||||
if (parentDir === currentDir) {
|
!isPathWithinWorkspace(parentDir, resolvedWorkspaceRoot)
|
||||||
break;
|
) {
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentDir = parentDir;
|
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(
|
function isPathWithinWorkspace(
|
||||||
checkPath: string,
|
checkPath: string,
|
||||||
workspaceRoot: string,
|
workspaceRoot: string,
|
||||||
): boolean | undefined {
|
): boolean {
|
||||||
try {
|
const relativePath = path.relative(workspaceRoot, checkPath);
|
||||||
const checkPathResolved = path.resolve(checkPath);
|
return !relativePath.startsWith("..") && !path.isAbsolute(relativePath);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-8
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
|
"esModuleInterop": true,
|
||||||
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
|
"isolatedModules": true,
|
||||||
"noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
|
"module": "esnext",
|
||||||
"outDir": "./lib" /* Redirect output structure to the directory. */,
|
"moduleResolution": "bundler",
|
||||||
"rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
|
"noImplicitAny": true,
|
||||||
"strict": true /* Enable all strict type-checking options. */,
|
"strict": true,
|
||||||
"target": "ES2022" /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
"target": "ES2022"
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules", "**/*.test.ts"]
|
"include": ["src/**/*.ts"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user