mirror of
https://github.com/astral-sh/ruff-action.git
synced 2026-08-08 18:27:03 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eef6392152 |
@@ -4,12 +4,12 @@
|
|||||||
"owner": "ruff-check",
|
"owner": "ruff-check",
|
||||||
"pattern": [
|
"pattern": [
|
||||||
{
|
{
|
||||||
"code": 4,
|
"regexp": "^Error: (.*):(\\d+):(\\d+): (\\w+) (.*)$",
|
||||||
"column": 3,
|
|
||||||
"file": 1,
|
"file": 1,
|
||||||
"line": 2,
|
"line": 2,
|
||||||
"message": 5,
|
"column": 3,
|
||||||
"regexp": "^Error: (.*):(\\d+):(\\d+): (\\w+) (.*)$"
|
"code": 4,
|
||||||
|
"message": 5
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,15 +4,9 @@
|
|||||||
"owner": "ruff-format",
|
"owner": "ruff-format",
|
||||||
"pattern": [
|
"pattern": [
|
||||||
{
|
{
|
||||||
"code": 2,
|
"regexp": "^(Would reformat):\\s*(.+)$",
|
||||||
"column": 5,
|
"message": 1,
|
||||||
"endColumn": 7,
|
"file": 2
|
||||||
"endLine": 6,
|
|
||||||
"file": 3,
|
|
||||||
"line": 4,
|
|
||||||
"message": 8,
|
|
||||||
"regexp": "^(?:(error|warning|notice))\\s+title=([^,]+),file=([^,]+),line=(\\d+),col=(\\d+)(?:,endLine=(\\d+))?(?:,endColumn=(\\d+))?::(.+)$",
|
|
||||||
"severity": 1
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
import * as fs from "node:fs";
|
|
||||||
import * as yaml from "js-yaml";
|
|
||||||
|
|
||||||
interface WorkflowJob {
|
|
||||||
needs?: string[];
|
|
||||||
[key: string]: unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Workflow {
|
|
||||||
jobs: Record<string, WorkflowJob>;
|
|
||||||
[key: string]: unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
const workflow = yaml.load(
|
|
||||||
fs.readFileSync("../workflows/test.yml", "utf8"),
|
|
||||||
) as Workflow;
|
|
||||||
const jobs = Object.keys(workflow.jobs);
|
|
||||||
const allTestsPassed = workflow.jobs["all-tests-passed"];
|
|
||||||
const needs: string[] = allTestsPassed.needs || [];
|
|
||||||
|
|
||||||
const expectedNeeds = jobs.filter((j) => j !== "all-tests-passed");
|
|
||||||
const missing = expectedNeeds.filter((j) => !needs.includes(j));
|
|
||||||
|
|
||||||
if (missing.length > 0) {
|
|
||||||
console.error(
|
|
||||||
`Missing jobs in all-tests-passed needs: ${missing.join(", ")}`,
|
|
||||||
);
|
|
||||||
console.info(
|
|
||||||
"Please add the missing jobs to the needs section of all-tests-passed in test.yml.",
|
|
||||||
);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
console.log(
|
|
||||||
"All jobs in test.yml are in the needs section of all-tests-passed.",
|
|
||||||
);
|
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# `dist/index.js` is a special file in Actions.
|
||||||
|
# When you reference an action with `uses:` in a workflow,
|
||||||
|
# `index.js` is the code that will run.
|
||||||
|
# For our project, we generate this file through a build process from other source files.
|
||||||
|
# We need to make sure the checked-in `index.js` actually matches what we expect it to be.
|
||||||
|
name: Check dist/
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-dist:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Node.js 20
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Rebuild the dist/ directory
|
||||||
|
run: |
|
||||||
|
npm run build
|
||||||
|
npm run package
|
||||||
|
|
||||||
|
- name: Compare the expected and actual dist/ directories
|
||||||
|
run: |
|
||||||
|
if [ "$(git diff --ignore-space-at-eol dist/ | wc -l)" -gt "0" ]; then
|
||||||
|
echo "Detected uncommitted changes after build. See status below:"
|
||||||
|
git diff --text -v
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
id: diff
|
||||||
|
|
||||||
|
# If index.js was different than expected, upload the expected version as an artifact
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
if: ${{ failure() && steps.diff.conclusion == 'failure' }}
|
||||||
|
with:
|
||||||
|
name: dist
|
||||||
|
path: dist/
|
||||||
@@ -12,7 +12,6 @@
|
|||||||
name: "CodeQL"
|
name: "CodeQL"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
pull_request:
|
pull_request:
|
||||||
@@ -39,13 +38,11 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
|
uses: github/codeql-action/init@v3
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
source-root: src
|
source-root: src
|
||||||
@@ -57,7 +54,7 @@ jobs:
|
|||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
|
uses: github/codeql-action/autobuild@v3
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 https://git.io/JvXDl
|
# 📚 https://git.io/JvXDl
|
||||||
@@ -71,4 +68,4 @@ jobs:
|
|||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
|
uses: github/codeql-action/analyze@v3
|
||||||
|
|||||||
@@ -3,20 +3,17 @@ name: Release Drafter
|
|||||||
|
|
||||||
# yamllint disable-line rule:truthy
|
# yamllint disable-line rule:truthy
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update_release_draft:
|
update_release_draft:
|
||||||
name: ✏️ Draft release
|
name: ✏️ Draft release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: read
|
|
||||||
steps:
|
steps:
|
||||||
- name: 🚀 Run Release Drafter
|
- name: 🚀 Run Release Drafter
|
||||||
uses: release-drafter/release-drafter@6db134d15f3909ccc9eefd369f02bd1e9cffdf97 # v6.2.0
|
uses: release-drafter/release-drafter@v6.0.0
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
+33
-302
@@ -1,7 +1,7 @@
|
|||||||
name: "test"
|
name: "test"
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
pull_request:
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
@@ -10,110 +10,51 @@ concurrency:
|
|||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
permissions: {}
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
|
||||||
security-events: write # for zizmor
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Actionlint
|
- name: Actionlint
|
||||||
uses: eifinger/actionlint-action@447fbfe7533062b7a9ea55f790f2396fba6d052a # v1.10.0
|
uses: eifinger/actionlint-action@8ebeb40569f3c15ca66fe36d1b75f9b70c6c4f6e # v1.9.0
|
||||||
- name: Run zizmor
|
- uses: actions/setup-node@v4
|
||||||
uses: zizmorcore/zizmor-action@135698455da5c3b3e55f73f4419e481ab68cdd95 # v0.4.1
|
|
||||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "20"
|
||||||
- run: |
|
- run: |
|
||||||
npm ci --ignore-scripts
|
npm install
|
||||||
- run: |
|
- run: |
|
||||||
npm run all
|
npm run all
|
||||||
- name: Check all jobs are in all-tests-passed.needs
|
|
||||||
run: |
|
|
||||||
tsc check-all-tests-passed-needs.ts
|
|
||||||
node check-all-tests-passed-needs.js
|
|
||||||
working-directory: .github/scripts
|
|
||||||
- name: Make sure no changes from linters are detected
|
- name: Make sure no changes from linters are detected
|
||||||
run: |
|
run: |
|
||||||
git diff --exit-code || (echo "::error::Please run 'npm run all' to fix the issues" && exit 1)
|
git diff --exit-code
|
||||||
test-latest-version:
|
test-latest-version:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest, macos-14, windows-latest]
|
os: [ubuntu-latest, macos-latest, macos-14, windows-latest]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Use latest version
|
- name: Use latest version
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
src: __tests__/fixtures/python-project
|
src: __tests__/fixtures/python-project
|
||||||
version: latest
|
version: latest
|
||||||
test-specific-version:
|
test-specific-version:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
ruff-version: ["0.1.7", "0.1.8", "0.4.7", "0.4.10", "0.7", "0.7.x", ">=0.7.0"]
|
ruff-version: ["0.7.4", "0.7", "0.7.x", ">=0.7.0"]
|
||||||
os: [ ubuntu-latest, ubuntu-24.04-arm, macos-latest, macos-14, windows-latest ]
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Use version ${{ matrix.ruff-version }}
|
- name: Use version ${{ matrix.ruff-version }}
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
version: ${{ matrix.ruff-version }}
|
version: ${{ matrix.ruff-version }}
|
||||||
src: __tests__/fixtures/python-project
|
src: __tests__/fixtures/python-project
|
||||||
test-unsupported-version:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Try install old version
|
|
||||||
id: install
|
|
||||||
continue-on-error: true
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
version: 0.0.246
|
|
||||||
src: __tests__/fixtures/python-project
|
|
||||||
- name: Check if the action failed
|
|
||||||
run: |
|
|
||||||
if [ "${INSTALL_OUTCOME}" == "success" ]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
env:
|
|
||||||
INSTALL_OUTCOME: ${{ steps.install.outcome }}
|
|
||||||
test-version-from-version-file-pyproject:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Use version from pyproject.toml
|
|
||||||
id: ruff-action
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
src: __tests__/fixtures/python-project
|
|
||||||
version-file: __tests__/fixtures/pyproject.toml
|
|
||||||
- name: Correct version gets installed
|
|
||||||
run: |
|
|
||||||
if [ "$RUFF_VERSION" != "0.9.3" ]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
env:
|
|
||||||
RUFF_VERSION: ${{ steps.ruff-action.outputs.ruff-version }}
|
|
||||||
test-default-version-from-pyproject:
|
test-default-version-from-pyproject:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Use default version from pyproject.toml
|
- name: Use default version from pyproject.toml
|
||||||
id: ruff-action
|
id: ruff-action
|
||||||
uses: ./
|
uses: ./
|
||||||
@@ -129,9 +70,7 @@ jobs:
|
|||||||
test-default-version-from-pyproject-dev-group:
|
test-default-version-from-pyproject-dev-group:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Use default version from pyproject.toml dev group
|
- name: Use default version from pyproject.toml dev group
|
||||||
id: ruff-action
|
id: ruff-action
|
||||||
uses: ./
|
uses: ./
|
||||||
@@ -145,146 +84,10 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
env:
|
env:
|
||||||
RUFF_VERSION: ${{ steps.ruff-action.outputs.ruff-version }}
|
RUFF_VERSION: ${{ steps.ruff-action.outputs.ruff-version }}
|
||||||
test-default-version-from-pyproject-dependency-groups:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Use default version from pyproject.toml dependency groups
|
|
||||||
id: ruff-action
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
src: __tests__/fixtures/pyproject-dependency-groups-project
|
|
||||||
version-file: __tests__/fixtures/pyproject-dependency-groups-project/pyproject.toml
|
|
||||||
- name: Correct version gets installed
|
|
||||||
run: |
|
|
||||||
if [ "$RUFF_VERSION" != "0.8.3" ]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
env:
|
|
||||||
RUFF_VERSION: ${{ steps.ruff-action.outputs.ruff-version }}
|
|
||||||
test-default-version-from-pyproject-dependency-groups-with-env-marker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Use default version from pyproject.toml with environment marker
|
|
||||||
id: ruff-action
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
src: __tests__/fixtures/python-project
|
|
||||||
version-file: __tests__/fixtures/pyproject-dependency-groups-with-env-marker/pyproject.toml
|
|
||||||
- name: Correct version gets installed
|
|
||||||
run: |
|
|
||||||
if [ "$RUFF_VERSION" != "0.13.3" ]; then
|
|
||||||
echo "Expected version 0.13.3 but got $RUFF_VERSION"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
env:
|
|
||||||
RUFF_VERSION: ${{ steps.ruff-action.outputs.ruff-version }}
|
|
||||||
test-default-version-from-pyproject-poetry-groups:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Use default version from pyproject.toml poetry group dependencies
|
|
||||||
id: ruff-action
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
src: __tests__/fixtures/pyproject-dependency-poetry-grouped-project
|
|
||||||
version-file: __tests__/fixtures/pyproject-dependency-poetry-grouped-project/pyproject.toml
|
|
||||||
- name: Correct version gets installed
|
|
||||||
run: |
|
|
||||||
if [ "$RUFF_VERSION" != "0.8.3" ]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
env:
|
|
||||||
RUFF_VERSION: ${{ steps.ruff-action.outputs.ruff-version }}
|
|
||||||
test-default-version-from-pyproject-poetry:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Use default version from pyproject.toml poetry dependencies
|
|
||||||
id: ruff-action
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
src: __tests__/fixtures/pyproject-dependency-poetry-project
|
|
||||||
version-file: __tests__/fixtures/pyproject-dependency-poetry-project/pyproject.toml
|
|
||||||
- name: Correct version gets installed
|
|
||||||
run: |
|
|
||||||
if [ "$RUFF_VERSION" != "0.8.6" ]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
env:
|
|
||||||
RUFF_VERSION: ${{ steps.ruff-action.outputs.ruff-version }}
|
|
||||||
test-default-version-from-pyproject-optional-dependencies:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Use default version from pyproject.toml optional dependencies
|
|
||||||
id: ruff-action
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
src: __tests__/fixtures/pyproject-optional-dependencies-project
|
|
||||||
version-file: __tests__/fixtures/pyproject-optional-dependencies-project/pyproject.toml
|
|
||||||
- name: Correct version gets installed
|
|
||||||
run: |
|
|
||||||
if [ "$RUFF_VERSION" != "0.8.3" ]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
env:
|
|
||||||
RUFF_VERSION: ${{ steps.ruff-action.outputs.ruff-version }}
|
|
||||||
test-default-version-from-requirements:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Use default version from requirements.txt
|
|
||||||
id: ruff-action
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
src: __tests__/fixtures/python-project
|
|
||||||
version-file: __tests__/fixtures/requirements.txt
|
|
||||||
- name: Correct version gets installed
|
|
||||||
run: |
|
|
||||||
if [ "$RUFF_VERSION" != "0.9.0" ]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
env:
|
|
||||||
RUFF_VERSION: ${{ steps.ruff-action.outputs.ruff-version }}
|
|
||||||
test-default-version-from-requirements-with-hash:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Use default version from requirements-with-hash.txt
|
|
||||||
id: ruff-action
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
src: __tests__/fixtures/python-project
|
|
||||||
version-file: __tests__/fixtures/requirements-with-hash.txt
|
|
||||||
- name: Correct version gets installed
|
|
||||||
run: |
|
|
||||||
if [ "$RUFF_VERSION" != "0.9.0" ]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
env:
|
|
||||||
RUFF_VERSION: ${{ steps.ruff-action.outputs.ruff-version }}
|
|
||||||
test-semver-range:
|
test-semver-range:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Use version 0.7
|
- name: Use version 0.7
|
||||||
id: ruff-action
|
id: ruff-action
|
||||||
uses: ./
|
uses: ./
|
||||||
@@ -298,50 +101,31 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
env:
|
env:
|
||||||
RUFF_VERSION: ${{ steps.ruff-action.outputs.ruff-version }}
|
RUFF_VERSION: ${{ steps.ruff-action.outputs.ruff-version }}
|
||||||
test-pep440-version-specifier:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Install version 0.9.10
|
|
||||||
id: ruff-action
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
version: ">=0.9.9,<0.10.0"
|
|
||||||
src: __tests__/fixtures/python-project
|
|
||||||
- name: Correct version gets installed
|
|
||||||
run: |
|
|
||||||
if [ "$RUFF_VERSION" != "0.9.10" ]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
env:
|
|
||||||
RUFF_VERSION: ${{ steps.ruff-action.outputs.ruff-version }}
|
|
||||||
test-checksum:
|
test-checksum:
|
||||||
runs-on: ${{ matrix.inputs.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
inputs:
|
os: [ubuntu-latest, macos-latest]
|
||||||
- os: ubuntu-latest
|
checksum:
|
||||||
|
["0de731c669b9ece77e799ac3f4a160c30849752714d9775c94cc4cfaf326860c"]
|
||||||
|
exclude:
|
||||||
|
- os: macos-latest
|
||||||
checksum: "0de731c669b9ece77e799ac3f4a160c30849752714d9775c94cc4cfaf326860c"
|
checksum: "0de731c669b9ece77e799ac3f4a160c30849752714d9775c94cc4cfaf326860c"
|
||||||
|
include:
|
||||||
- os: macos-latest
|
- os: macos-latest
|
||||||
checksum: "af9583bff12afbca5d5670334e0187dd60c4d91bc71317d1b2dde70cb1200ba9"
|
checksum: "af9583bff12afbca5d5670334e0187dd60c4d91bc71317d1b2dde70cb1200ba9"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Checksum matches expected
|
- name: Checksum matches expected
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
version: "0.7.4"
|
version: "0.7.4"
|
||||||
checksum: ${{ matrix.inputs.checksum }}
|
checksum: ${{ matrix.checksum }}
|
||||||
src: __tests__/fixtures/python-project
|
src: __tests__/fixtures/python-project
|
||||||
test-with-explicit-token:
|
test-with-explicit-token:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Use default version
|
- name: Use default version
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
@@ -353,9 +137,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Use args
|
- name: Use args
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
@@ -364,9 +146,7 @@ jobs:
|
|||||||
test-failure:
|
test-failure:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Format should fail
|
- name: Format should fail
|
||||||
id: format-should-fail
|
id: format-should-fail
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
@@ -376,11 +156,9 @@ jobs:
|
|||||||
src: __tests__/fixtures/malformed-python-project
|
src: __tests__/fixtures/malformed-python-project
|
||||||
- name: Check if the action failed
|
- name: Check if the action failed
|
||||||
run: |
|
run: |
|
||||||
if [ "${FORMAT_SHOULD_FAIL_OUTCOME}" == "success" ]; then
|
if [ ${{ steps.format-should-fail.outcome }} == "success" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
env:
|
|
||||||
FORMAT_SHOULD_FAIL_OUTCOME: ${{ steps.format-should-fail.outcome }}
|
|
||||||
- name: Check should fail
|
- name: Check should fail
|
||||||
id: check-should-fail
|
id: check-should-fail
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
@@ -389,20 +167,16 @@ jobs:
|
|||||||
src: __tests__/fixtures/malformed-python-project
|
src: __tests__/fixtures/malformed-python-project
|
||||||
- name: Check if the action failed
|
- name: Check if the action failed
|
||||||
run: |
|
run: |
|
||||||
if [ "${CHECK_SHOULD_FAIL_OUTCOME}" == "success" ]; then
|
if [ ${{ steps.check-should-fail.outcome }} == "success" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
env:
|
|
||||||
CHECK_SHOULD_FAIL_OUTCOME: ${{ steps.check-should-fail.outcome }}
|
|
||||||
test-multiple-src:
|
test-multiple-src:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ ubuntu-latest, windows-latest ]
|
os: [ ubuntu-latest, windows-latest ]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Use args
|
- name: Use args
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
@@ -410,55 +184,12 @@ jobs:
|
|||||||
src: >-
|
src: >-
|
||||||
__tests__/fixtures/python-project/src/python_project/__init__.py
|
__tests__/fixtures/python-project/src/python_project/__init__.py
|
||||||
__tests__/fixtures/python-project/src/python_project/hello_world.py
|
__tests__/fixtures/python-project/src/python_project/hello_world.py
|
||||||
test-parent-directory-pyproject:
|
test-exit-zero:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v4
|
||||||
with:
|
- name: Debug this
|
||||||
persist-credentials: false
|
|
||||||
- name: Use version from parent directory pyproject.toml
|
|
||||||
id: ruff-action
|
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
src: __tests__/fixtures/parent-config-project/subproject
|
args: "--exit-zero"
|
||||||
- name: Correct version gets installed
|
src: __tests__/fixtures/python-project
|
||||||
run: |
|
|
||||||
if [ "$RUFF_VERSION" != "0.10.0" ]; then
|
|
||||||
echo "Expected version 0.10.0 but got $RUFF_VERSION"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
env:
|
|
||||||
RUFF_VERSION: ${{ steps.ruff-action.outputs.ruff-version }}
|
|
||||||
|
|
||||||
all-tests-passed:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- lint
|
|
||||||
- test-latest-version
|
|
||||||
- test-specific-version
|
|
||||||
- test-unsupported-version
|
|
||||||
- test-version-from-version-file-pyproject
|
|
||||||
- test-default-version-from-pyproject
|
|
||||||
- test-default-version-from-pyproject-dev-group
|
|
||||||
- test-default-version-from-pyproject-dependency-groups
|
|
||||||
- test-default-version-from-pyproject-dependency-groups-with-env-marker
|
|
||||||
- test-default-version-from-pyproject-poetry-groups
|
|
||||||
- test-default-version-from-pyproject-poetry
|
|
||||||
- test-default-version-from-pyproject-optional-dependencies
|
|
||||||
- test-default-version-from-requirements
|
|
||||||
- test-default-version-from-requirements-with-hash
|
|
||||||
- test-semver-range
|
|
||||||
- test-pep440-version-specifier
|
|
||||||
- test-checksum
|
|
||||||
- test-with-explicit-token
|
|
||||||
- test-args
|
|
||||||
- test-failure
|
|
||||||
- test-multiple-src
|
|
||||||
- test-parent-directory-pyproject
|
|
||||||
if: always()
|
|
||||||
steps:
|
|
||||||
- name: All tests passed
|
|
||||||
run: |
|
|
||||||
echo "All jobs passed: ${{ !(contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')) }}"
|
|
||||||
# shellcheck disable=SC2242
|
|
||||||
exit ${{ (contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')) && 1 || 0 }}
|
|
||||||
|
|||||||
@@ -1,20 +1,13 @@
|
|||||||
name: "Update known checksums"
|
name: "Update known checksums"
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
|
||||||
- cron: "0 4 * * *" # Run every day at 4am UTC
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v4
|
||||||
with:
|
- uses: actions/setup-node@v4
|
||||||
persist-credentials: false
|
|
||||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "20"
|
||||||
- name: Update known checksums
|
- name: Update known checksums
|
||||||
@@ -22,9 +15,9 @@ jobs:
|
|||||||
run:
|
run:
|
||||||
node dist/update-known-checksums/index.js
|
node dist/update-known-checksums/index.js
|
||||||
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 install && npm run all
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
|
uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6
|
||||||
with:
|
with:
|
||||||
commit-message: "chore: update known checksums"
|
commit-message: "chore: update known checksums"
|
||||||
title:
|
title:
|
||||||
|
|||||||
@@ -13,38 +13,7 @@ jobs:
|
|||||||
update_major_minor_tags:
|
update_major_minor_tags:
|
||||||
name: Make sure major and minor tags are up to date on a patch release
|
name: Make sure major and minor tags are up to date on a patch release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v4
|
||||||
with:
|
- name: Run Update semver
|
||||||
persist-credentials: true
|
uses: haya14busa/action-update-semver@v1.2.1
|
||||||
- name: Update Major Minor Tags
|
|
||||||
run: |
|
|
||||||
set -x
|
|
||||||
|
|
||||||
cd "${GITHUB_WORKSPACE}" || exit
|
|
||||||
|
|
||||||
# Set up variables.
|
|
||||||
TAG="${GITHUB_REF#refs/tags/}" # v1.2.3
|
|
||||||
MINOR="${TAG%.*}" # v1.2
|
|
||||||
MAJOR="${MINOR%.*}" # v1
|
|
||||||
|
|
||||||
if [ "${GITHUB_REF}" = "${TAG}" ]; then
|
|
||||||
echo "This workflow is not triggered by tag push: GITHUB_REF=${GITHUB_REF}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
MESSAGE="Release ${TAG}"
|
|
||||||
|
|
||||||
# Set up Git.
|
|
||||||
git config user.name "${GITHUB_ACTOR}"
|
|
||||||
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
|
|
||||||
|
|
||||||
# Update MAJOR/MINOR tag
|
|
||||||
git tag -fa "${MAJOR}" -m "${MESSAGE}"
|
|
||||||
git tag -fa "${MINOR}" -m "${MESSAGE}"
|
|
||||||
|
|
||||||
# Push
|
|
||||||
git push --force origin "${MINOR}"
|
|
||||||
git push --force origin "${MAJOR}"
|
|
||||||
|
|||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"recommendations": ["biomejs.biome"]
|
|
||||||
}
|
|
||||||
Vendored
-16
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"editor.codeActionsOnSave": {
|
|
||||||
"source.action.useSortedAttributes.biome": "explicit",
|
|
||||||
"source.action.useSortedKeys.biome": "explicit",
|
|
||||||
"source.fixAll.biome": "explicit"
|
|
||||||
},
|
|
||||||
"editor.defaultFormatter": "biomejs.biome",
|
|
||||||
"editor.formatOnSave": true,
|
|
||||||
"explorer.excludeGitIgnore": false,
|
|
||||||
"search.defaultViewMode": "list",
|
|
||||||
"search.exclude": {
|
|
||||||
"**/node_modules": true
|
|
||||||
},
|
|
||||||
"typescript.enablePromptUseWorkspaceTsdk": true,
|
|
||||||
"typescript.tsdk": "node_modules/typescript/lib"
|
|
||||||
}
|
|
||||||
@@ -4,8 +4,8 @@ A GitHub Action to run [ruff](https://github.com/astral-sh/ruff).
|
|||||||
|
|
||||||
This action is commonly used as a pass/fail test to ensure your repository stays
|
This action is commonly used as a pass/fail test to ensure your repository stays
|
||||||
clean, abiding the [rules](https://docs.astral.sh/ruff/rules/) specified in your
|
clean, abiding the [rules](https://docs.astral.sh/ruff/rules/) specified in your
|
||||||
configuration. Though it runs `ruff check` by default, the action can do
|
configuration. Though it runs `ruff`, the action can do anything `ruff` can (ex,
|
||||||
anything `ruff` can (ex, fix).
|
fix).
|
||||||
|
|
||||||
## Contents
|
## Contents
|
||||||
|
|
||||||
@@ -16,9 +16,9 @@ anything `ruff` can (ex, fix).
|
|||||||
- [Use to install ruff](#use-to-install-ruff)
|
- [Use to install ruff](#use-to-install-ruff)
|
||||||
- [Use `ruff format`](#use-ruff-format)
|
- [Use `ruff format`](#use-ruff-format)
|
||||||
- [Install specific versions](#install-specific-versions)
|
- [Install specific versions](#install-specific-versions)
|
||||||
- [Install the latest version](#install-the-latest-version)
|
- [Install the latest version (default)](#install-the-latest-version-default)
|
||||||
- [Install a specific version](#install-a-specific-version)
|
- [Install a specific version](#install-a-specific-version)
|
||||||
- [Install a version by supplying a semver range or pep440 specifier](#install-a-version-by-supplying-a-semver-range-or-pep440-specifier)
|
- [Install a version by supplying a semver range](#install-a-version-by-supplying-a-semver-range)
|
||||||
- [Install a version from a specified version file](#install-a-version-from-a-specified-version-file)
|
- [Install a version from a specified version file](#install-a-version-from-a-specified-version-file)
|
||||||
- [Validate checksum](#validate-checksum)
|
- [Validate checksum](#validate-checksum)
|
||||||
- [GitHub authentication token](#github-authentication-token)
|
- [GitHub authentication token](#github-authentication-token)
|
||||||
@@ -69,34 +69,19 @@ This action adds ruff to the PATH, so you can use it in subsequent steps.
|
|||||||
- run: ruff format
|
- run: ruff format
|
||||||
```
|
```
|
||||||
|
|
||||||
By default, this action runs `ruff check` after installation.
|
|
||||||
If you do not want to run any `ruff` command but only install it,
|
|
||||||
you can use the `args` input to overwrite the default value (`check`):
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- name: Install ruff without running check or format
|
|
||||||
uses: astral-sh/ruff-action@v3
|
|
||||||
with:
|
|
||||||
args: "--version"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Use `ruff format`
|
### Use `ruff format`
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: astral-sh/ruff-action@v3
|
- uses: astral-sh/ruff-action@v3
|
||||||
with:
|
with:
|
||||||
args: "format --check --diff"
|
args: "format --check"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Install specific versions
|
### Install specific versions
|
||||||
|
|
||||||
By default this action looks for a pyproject.toml file in the root of the repository to determine
|
By default this action looks for a pyproject.toml file in the root of the repository to determine
|
||||||
the ruff version to install. If no pyproject.toml file is found, or no ruff version is defined in
|
the ruff version to install. If no pyproject.toml file is found, or no ruff version is defined in
|
||||||
`project.dependencies`, `project.optional-dependencies`, or `dependency-groups`,
|
either `dependencies` or `dependency-groups.dev` the latest version is installed.
|
||||||
the latest version is installed.
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> This action does only support ruff versions v0.0.247 and above.
|
|
||||||
|
|
||||||
#### Install the latest version
|
#### Install the latest version
|
||||||
|
|
||||||
@@ -116,10 +101,9 @@ the latest version is installed.
|
|||||||
version: "0.4.4"
|
version: "0.4.4"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Install a version by supplying a semver range or pep440 specifier
|
#### Install a version by supplying a semver range
|
||||||
|
|
||||||
You can specify a [semver range](https://github.com/npm/node-semver?tab=readme-ov-file#ranges)
|
You can specify a [semver range](https://github.com/npm/node-semver?tab=readme-ov-file#ranges)
|
||||||
or [pep440 specifier](https://peps.python.org/pep-0440/#version-specifiers)
|
|
||||||
to install the latest version that satisfies the range.
|
to install the latest version that satisfies the range.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -136,23 +120,16 @@ to install the latest version that satisfies the range.
|
|||||||
version: "0.4.x"
|
version: "0.4.x"
|
||||||
```
|
```
|
||||||
|
|
||||||
```yaml
|
|
||||||
- name: Install a pep440-specifier-satisfying version of ruff
|
|
||||||
uses: astral-sh/ruff-action@v3
|
|
||||||
with:
|
|
||||||
version: ">=0.11.10,<0.12.0"
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Install a version from a specified version file
|
#### Install a version from a specified version file
|
||||||
|
|
||||||
You can specify a file to read the version from.
|
You can specify a file to read the version from.
|
||||||
Currently `pyproject.toml` and `requirements.txt` are supported.
|
Currently `pyproject.toml` is supported.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Install a version from a specified version file
|
- name: Install a version from a specified version file
|
||||||
uses: astral-sh/ruff-action@v3
|
uses: astral-sh/ruff-action@v3
|
||||||
with:
|
with:
|
||||||
version-file: "my-path/to/pyproject.toml-or-requirements.txt"
|
version-file: "my-path/to/pyproject.toml"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Validate checksum
|
### Validate checksum
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
[project]
|
|
||||||
name = "parent-config-project"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "Test fixture for parent directory pyproject.toml search"
|
|
||||||
readme = "README.md"
|
|
||||||
requires-python = ">=3.12"
|
|
||||||
dependencies = [
|
|
||||||
"ruff==0.10.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[build-system]
|
|
||||||
requires = ["hatchling"]
|
|
||||||
build-backend = "hatchling.build"
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
"""Hello world example."""
|
|
||||||
|
|
||||||
print("Hello, world!")
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
[project]
|
|
||||||
name = "pyproject-dependency-groups-project"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "Add your description here"
|
|
||||||
readme = "README.md"
|
|
||||||
requires-python = ">=3.12"
|
|
||||||
|
|
||||||
[dependency-groups]
|
|
||||||
dev = [
|
|
||||||
{ include-group = "docs" },
|
|
||||||
{ include-group = "lint" },
|
|
||||||
]
|
|
||||||
docs = [
|
|
||||||
"sphinx",
|
|
||||||
]
|
|
||||||
lint = [
|
|
||||||
"ruff==0.8.3",
|
|
||||||
]
|
|
||||||
|
|
||||||
[build-system]
|
|
||||||
requires = ["hatchling"]
|
|
||||||
build-backend = "hatchling.build"
|
|
||||||
-2
@@ -1,2 +0,0 @@
|
|||||||
def hello() -> str:
|
|
||||||
return "Hello from python-project!"
|
|
||||||
-1
@@ -1 +0,0 @@
|
|||||||
print("Hello world!")
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
[project]
|
|
||||||
name = "pyproject-dependency-groups-with-env-marker"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "Test fixture for issue #256 - environment markers"
|
|
||||||
readme = "README.md"
|
|
||||||
requires-python = ">=3.12"
|
|
||||||
|
|
||||||
[dependency-groups]
|
|
||||||
dev = [
|
|
||||||
"ruff~=0.13 ; python_version >= '3.11'",
|
|
||||||
]
|
|
||||||
|
|
||||||
[build-system]
|
|
||||||
requires = ["hatchling"]
|
|
||||||
build-backend = "hatchling.build"
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
[project]
|
|
||||||
name = "pyproject-dependency-poetry-grouped-project"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "Add your description here"
|
|
||||||
readme = "README.md"
|
|
||||||
requires-python = ">=3.12"
|
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
|
||||||
sphinx = "*"
|
|
||||||
ruff = "0.8.3"
|
|
||||||
|
|
||||||
[build-system]
|
|
||||||
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
||||||
build-backend = "poetry.core.masonry.api"
|
|
||||||
-2
@@ -1,2 +0,0 @@
|
|||||||
def hello() -> str:
|
|
||||||
return "Hello from python-project!"
|
|
||||||
-1
@@ -1 +0,0 @@
|
|||||||
print("Hello world!")
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
[project]
|
|
||||||
name = "pyproject-dependency-poetry-project"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "Add your description here"
|
|
||||||
readme = "README.md"
|
|
||||||
requires-python = ">=3.12"
|
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
|
||||||
sphinx = "*"
|
|
||||||
ruff = "~0.8.2"
|
|
||||||
|
|
||||||
[build-system]
|
|
||||||
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
||||||
build-backend = "poetry.core.masonry.api"
|
|
||||||
-2
@@ -1,2 +0,0 @@
|
|||||||
def hello() -> str:
|
|
||||||
return "Hello from python-project!"
|
|
||||||
-1
@@ -1 +0,0 @@
|
|||||||
print("Hello world!")
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
[project]
|
|
||||||
name = "pyproject-optional-dependencies-project"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "Add your description here"
|
|
||||||
readme = "README.md"
|
|
||||||
requires-python = ">=3.12"
|
|
||||||
|
|
||||||
[project.optional-dependencies]
|
|
||||||
lint = [
|
|
||||||
"ruff==0.8.3",
|
|
||||||
]
|
|
||||||
|
|
||||||
[build-system]
|
|
||||||
requires = ["hatchling"]
|
|
||||||
build-backend = "hatchling.build"
|
|
||||||
-2
@@ -1,2 +0,0 @@
|
|||||||
def hello() -> str:
|
|
||||||
return "Hello from python-project!"
|
|
||||||
-1
@@ -1 +0,0 @@
|
|||||||
print("Hello world!")
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
[project]
|
|
||||||
name = "pyython-project"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "Add your description here"
|
|
||||||
readme = "README.md"
|
|
||||||
requires-python = ">=3.12"
|
|
||||||
dependencies = [
|
|
||||||
"ruff==0.9.3",
|
|
||||||
]
|
|
||||||
|
|
||||||
[build-system]
|
|
||||||
requires = ["hatchling"]
|
|
||||||
build-backend = "hatchling.build"
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
ruff==0.9.0 \
|
|
||||||
--hash=sha256:badc0de
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
ruff==0.9.0
|
|
||||||
+13
-27
@@ -1,35 +1,20 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://biomejs.dev/schemas/2.3.2/schema.json",
|
"$schema": "https://biomejs.dev/schemas/1.9.2/schema.json",
|
||||||
"assist": {
|
"vcs": {
|
||||||
"actions": {
|
"enabled": true,
|
||||||
"source": {
|
"clientKind": "git",
|
||||||
"organizeImports": "on",
|
"useIgnoreFile": false
|
||||||
"useSortedAttributes": "on",
|
|
||||||
"useSortedKeys": "on"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"ignoreUnknown": false,
|
"ignoreUnknown": false,
|
||||||
"includes": [
|
"ignore": ["dist", "lib", "node_modules"]
|
||||||
"**",
|
|
||||||
"!**/coverage",
|
|
||||||
"!**/dist",
|
|
||||||
"!**/lib",
|
|
||||||
"!**/node_modules",
|
|
||||||
"!**/package*.json",
|
|
||||||
"!**/known-checksums.*"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"formatter": {
|
"formatter": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"indentStyle": "space"
|
"indentStyle": "space"
|
||||||
},
|
},
|
||||||
"javascript": {
|
"organizeImports": {
|
||||||
"formatter": {
|
"enabled": true
|
||||||
"quoteStyle": "double",
|
|
||||||
"trailingCommas": "all"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"linter": {
|
"linter": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
@@ -37,9 +22,10 @@
|
|||||||
"recommended": true
|
"recommended": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"vcs": {
|
"javascript": {
|
||||||
"clientKind": "git",
|
"formatter": {
|
||||||
"enabled": true,
|
"quoteStyle": "double",
|
||||||
"useIgnoreFile": false
|
"trailingCommas": "all"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4535
-6130
File diff suppressed because it is too large
Load Diff
+4424
-5013
File diff suppressed because it is too large
Load Diff
@@ -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",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
Generated
+189
-3972
File diff suppressed because it is too large
Load Diff
+12
-23
@@ -6,45 +6,34 @@
|
|||||||
"main": "dist/ruff-action/index.js",
|
"main": "dist/ruff-action/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"check": "biome check --write",
|
"format": "biome format --fix",
|
||||||
|
"format-check": "biome format",
|
||||||
|
"lint": "biome lint --fix",
|
||||||
"package": "ncc build -o dist/ruff-action src/ruff-action.ts && ncc build -o dist/update-known-checksums src/update-known-checksums.ts",
|
"package": "ncc build -o dist/ruff-action src/ruff-action.ts && ncc build -o dist/update-known-checksums src/update-known-checksums.ts",
|
||||||
"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.js src/download/checksum/known-checksums.ts \"$(gh auth token)\"",
|
||||||
"test": "jest",
|
"all": "npm run build && npm run format && npm run lint && npm run package"
|
||||||
"all": "npm ci --ignore-scripts && npm run build && npm run check && npm run test && npm run package"
|
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/astral-sh/ruff-action.git"
|
"url": "git+https://github.com/astral-sh/ruff-action.git"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": ["actions", "python", "ruff", "action"],
|
||||||
"actions",
|
|
||||||
"python",
|
|
||||||
"ruff",
|
|
||||||
"action"
|
|
||||||
],
|
|
||||||
"author": "@eifinger",
|
"author": "@eifinger",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.11.1",
|
"@actions/core": "^1.11.1",
|
||||||
"@actions/exec": "^1.1.1",
|
"@actions/exec": "^1.1.1",
|
||||||
"@actions/tool-cache": "^2.0.2",
|
"@actions/github": "^6.0.0",
|
||||||
"@octokit/core": "^7.0.3",
|
"@actions/tool-cache": "^2.0.1",
|
||||||
"@octokit/plugin-paginate-rest": "^13.1.1",
|
"smol-toml": "^1.3.1"
|
||||||
"@octokit/plugin-rest-endpoint-methods": "^16.0.0",
|
|
||||||
"@renovatebot/pep440": "^4.2.1",
|
|
||||||
"smol-toml": "^1.6.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "2.3.2",
|
"@biomejs/biome": "1.9.4",
|
||||||
"@types/jest": "^29.5.14",
|
"@types/node": "^22.10.5",
|
||||||
"@types/js-yaml": "^4.0.9",
|
"@types/semver": "^7.5.8",
|
||||||
"@types/node": "^24.10.9",
|
|
||||||
"@types/semver": "^7.7.1",
|
|
||||||
"@vercel/ncc": "^0.38.3",
|
"@vercel/ncc": "^0.38.3",
|
||||||
"jest": "^29.7.0",
|
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"ts-jest": "^29.2.5",
|
"typescript": "^5.6.3"
|
||||||
"typescript": "^5.9.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import * as crypto from "node:crypto";
|
|
||||||
import * as fs from "node:fs";
|
import * as fs from "node:fs";
|
||||||
|
import * as crypto from "node:crypto";
|
||||||
|
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
import type { Architecture, Platform } from "../../utils/platforms";
|
|
||||||
import { KNOWN_CHECKSUMS } from "./known-checksums";
|
import { KNOWN_CHECKSUMS } from "./known-checksums";
|
||||||
|
import type { Architecture, Platform } from "../../utils/platforms";
|
||||||
|
|
||||||
export async function validateChecksum(
|
export async function validateChecksum(
|
||||||
checkSum: string | undefined,
|
checkSum: string | undefined,
|
||||||
@@ -12,7 +12,7 @@ export async function validateChecksum(
|
|||||||
platform: Platform,
|
platform: Platform,
|
||||||
version: string,
|
version: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
let isValid: boolean | undefined;
|
let isValid: boolean | undefined = undefined;
|
||||||
if (checkSum !== undefined && checkSum !== "") {
|
if (checkSum !== undefined && checkSum !== "") {
|
||||||
isValid = await validateFileCheckSum(downloadPath, checkSum);
|
isValid = await validateFileCheckSum(downloadPath, checkSum);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,17 +1,11 @@
|
|||||||
import { promises as fs } from "node:fs";
|
|
||||||
import * as path from "node:path";
|
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
import * as tc from "@actions/tool-cache";
|
import * as tc from "@actions/tool-cache";
|
||||||
import { Octokit } from "@octokit/core";
|
import * as path from "node:path";
|
||||||
import { paginateRest } from "@octokit/plugin-paginate-rest";
|
import { promises as fs } from "node:fs";
|
||||||
import { restEndpointMethods } from "@octokit/plugin-rest-endpoint-methods";
|
|
||||||
import * as pep440 from "@renovatebot/pep440";
|
|
||||||
import * as semver from "semver";
|
|
||||||
import { OWNER, REPO, TOOL_CACHE_NAME } from "../utils/constants";
|
import { OWNER, REPO, TOOL_CACHE_NAME } from "../utils/constants";
|
||||||
import type { Architecture, Platform } from "../utils/platforms";
|
import type { Architecture, Platform } from "../utils/platforms";
|
||||||
import { validateChecksum } from "./checksum/checksum";
|
import { validateChecksum } from "./checksum/checksum";
|
||||||
|
import * as github from "@actions/github";
|
||||||
const PaginatingOctokit = Octokit.plugin(paginateRest, restEndpointMethods);
|
|
||||||
|
|
||||||
export function tryGetFromToolCache(
|
export function tryGetFromToolCache(
|
||||||
arch: Architecture,
|
arch: Architecture,
|
||||||
@@ -25,7 +19,7 @@ export function tryGetFromToolCache(
|
|||||||
resolvedVersion = version;
|
resolvedVersion = version;
|
||||||
}
|
}
|
||||||
const installedPath = tc.find(TOOL_CACHE_NAME, resolvedVersion, arch);
|
const installedPath = tc.find(TOOL_CACHE_NAME, resolvedVersion, arch);
|
||||||
return { installedPath, version: resolvedVersion };
|
return { version: resolvedVersion, installedPath };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function downloadVersion(
|
export async function downloadVersion(
|
||||||
@@ -40,59 +34,16 @@ export async function downloadVersion(
|
|||||||
if (platform === "pc-windows-msvc") {
|
if (platform === "pc-windows-msvc") {
|
||||||
extension = ".zip";
|
extension = ".zip";
|
||||||
}
|
}
|
||||||
const downloadUrl = constructDownloadUrl(version, platform, arch);
|
const downloadUrl = `https://github.com/${OWNER}/${REPO}/releases/download/${version}/${artifact}${extension}`;
|
||||||
core.debug(`Downloading ruff from "${downloadUrl}" ...`);
|
core.info(`Downloading ruff from "${downloadUrl}" ...`);
|
||||||
|
|
||||||
const downloadPath = await tc.downloadTool(
|
const downloadPath = await tc.downloadTool(
|
||||||
downloadUrl,
|
downloadUrl,
|
||||||
undefined,
|
undefined,
|
||||||
githubToken,
|
githubToken,
|
||||||
);
|
);
|
||||||
core.debug(`Downloaded ruff to "${downloadPath}"`);
|
|
||||||
await validateChecksum(checkSum, downloadPath, arch, platform, version);
|
await validateChecksum(checkSum, downloadPath, arch, platform, version);
|
||||||
|
|
||||||
const extractedDir = await extractDownloadedArtifact(
|
|
||||||
version,
|
|
||||||
downloadPath,
|
|
||||||
extension,
|
|
||||||
platform,
|
|
||||||
artifact,
|
|
||||||
);
|
|
||||||
|
|
||||||
const cachedToolDir = await tc.cacheDir(
|
|
||||||
extractedDir,
|
|
||||||
TOOL_CACHE_NAME,
|
|
||||||
version,
|
|
||||||
arch,
|
|
||||||
);
|
|
||||||
return { cachedToolDir, version: version };
|
|
||||||
}
|
|
||||||
|
|
||||||
function constructDownloadUrl(
|
|
||||||
version: string,
|
|
||||||
platform: Platform,
|
|
||||||
arch: Architecture,
|
|
||||||
): string {
|
|
||||||
const artifactVersionSuffix =
|
|
||||||
semver.lte(version, "v0.4.10") && semver.gte(version, "v0.1.8")
|
|
||||||
? `-${version}`
|
|
||||||
: "";
|
|
||||||
const artifact = `ruff${artifactVersionSuffix}-${arch}-${platform}`;
|
|
||||||
let extension = ".tar.gz";
|
|
||||||
if (platform === "pc-windows-msvc") {
|
|
||||||
extension = ".zip";
|
|
||||||
}
|
|
||||||
const versionPrefix = semver.lte(version, "v0.4.10") ? "v" : "";
|
|
||||||
return `https://github.com/${OWNER}/${REPO}/releases/download/${versionPrefix}${version}/${artifact}${extension}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function extractDownloadedArtifact(
|
|
||||||
version: string,
|
|
||||||
downloadPath: string,
|
|
||||||
extension: string,
|
|
||||||
platform: Platform,
|
|
||||||
artifact: string,
|
|
||||||
): Promise<string> {
|
|
||||||
let ruffDir: string;
|
let ruffDir: string;
|
||||||
if (platform === "pc-windows-msvc") {
|
if (platform === "pc-windows-msvc") {
|
||||||
const fullPathWithExtension = `${downloadPath}${extension}`;
|
const fullPathWithExtension = `${downloadPath}${extension}`;
|
||||||
@@ -100,22 +51,22 @@ async function extractDownloadedArtifact(
|
|||||||
ruffDir = await tc.extractZip(fullPathWithExtension);
|
ruffDir = await tc.extractZip(fullPathWithExtension);
|
||||||
// On windows extracting the zip does not create an intermediate directory
|
// On windows extracting the zip does not create an intermediate directory
|
||||||
} else {
|
} else {
|
||||||
ruffDir = await tc.extractTar(downloadPath);
|
const extractedDir = await tc.extractTar(downloadPath);
|
||||||
if (semver.gte(version, "v0.5.0")) {
|
ruffDir = path.join(extractedDir, artifact);
|
||||||
// Since v0.5.0 an intermediate directory is created
|
|
||||||
ruffDir = path.join(ruffDir, artifact);
|
|
||||||
}
|
}
|
||||||
}
|
const cachedToolDir = await tc.cacheDir(
|
||||||
const files = await fs.readdir(ruffDir);
|
ruffDir,
|
||||||
core.debug(`Contents of ${ruffDir}: ${files.join(", ")}`);
|
TOOL_CACHE_NAME,
|
||||||
return ruffDir;
|
version,
|
||||||
|
arch,
|
||||||
|
);
|
||||||
|
return { version: version, cachedToolDir };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function resolveVersion(
|
export async function resolveVersion(
|
||||||
versionInput: string,
|
versionInput: string,
|
||||||
githubToken: string,
|
githubToken: string,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
core.debug(`Resolving ${versionInput}...`);
|
|
||||||
const version =
|
const version =
|
||||||
versionInput === "latest"
|
versionInput === "latest"
|
||||||
? await getLatestVersion(githubToken)
|
? await getLatestVersion(githubToken)
|
||||||
@@ -125,102 +76,33 @@ export async function resolveVersion(
|
|||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
const availableVersions = await getAvailableVersions(githubToken);
|
const availableVersions = await getAvailableVersions(githubToken);
|
||||||
const resolvedVersion = maxSatisfying(availableVersions, version);
|
const resolvedVersion = tc.evaluateVersions(availableVersions, version);
|
||||||
if (resolvedVersion === undefined) {
|
if (resolvedVersion === "") {
|
||||||
throw new Error(`No version found for ${version}`);
|
throw new Error(`No version found for ${version}`);
|
||||||
}
|
}
|
||||||
core.debug(`Resolved version: ${resolvedVersion}`);
|
|
||||||
return resolvedVersion;
|
return resolvedVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAvailableVersions(githubToken: string): Promise<string[]> {
|
async function getAvailableVersions(githubToken: string): Promise<string[]> {
|
||||||
try {
|
const octokit = github.getOctokit(githubToken);
|
||||||
const octokit = new PaginatingOctokit({
|
|
||||||
auth: githubToken,
|
|
||||||
});
|
|
||||||
return await getReleaseTagNames(octokit);
|
|
||||||
} catch (err) {
|
|
||||||
if ((err as Error).message.includes("Bad credentials")) {
|
|
||||||
core.info(
|
|
||||||
"No (valid) GitHub token provided. Falling back to anonymous. Requests might be rate limited.",
|
|
||||||
);
|
|
||||||
const octokit = new PaginatingOctokit();
|
|
||||||
return await getReleaseTagNames(octokit);
|
|
||||||
}
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getReleaseTagNames(
|
|
||||||
octokit: InstanceType<typeof PaginatingOctokit>,
|
|
||||||
): Promise<string[]> {
|
|
||||||
const response = await octokit.paginate(octokit.rest.repos.listReleases, {
|
const response = await octokit.paginate(octokit.rest.repos.listReleases, {
|
||||||
owner: OWNER,
|
owner: OWNER,
|
||||||
repo: REPO,
|
repo: REPO,
|
||||||
});
|
});
|
||||||
const releaseTagNames = response.map((release) => release.tag_name);
|
|
||||||
if (releaseTagNames.length === 0) {
|
|
||||||
throw Error(
|
|
||||||
"Github API request failed while getting releases. Check the GitHub status page for outages. Try again later.",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return response.map((release) => release.tag_name);
|
return response.map((release) => release.tag_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getLatestVersion(githubToken: string) {
|
async function getLatestVersion(githubToken: string) {
|
||||||
const octokit = new PaginatingOctokit({
|
const octokit = github.getOctokit(githubToken);
|
||||||
auth: githubToken,
|
|
||||||
});
|
|
||||||
|
|
||||||
let latestRelease: { tag_name: string } | undefined;
|
const { data: latestRelease } = await octokit.rest.repos.getLatestRelease({
|
||||||
try {
|
owner: OWNER,
|
||||||
latestRelease = await getLatestRelease(octokit);
|
repo: REPO,
|
||||||
} catch (err) {
|
});
|
||||||
if ((err as Error).message.includes("Bad credentials")) {
|
|
||||||
core.info(
|
|
||||||
"No (valid) GitHub token provided. Falling back to anonymous. Requests might be rate limited.",
|
|
||||||
);
|
|
||||||
const octokit = new PaginatingOctokit();
|
|
||||||
latestRelease = await getLatestRelease(octokit);
|
|
||||||
} else {
|
|
||||||
core.error(
|
|
||||||
"Github API request failed while getting latest release. Check the GitHub status page for outages. Try again later.",
|
|
||||||
);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!latestRelease) {
|
if (!latestRelease) {
|
||||||
throw new Error("Could not determine latest release.");
|
throw new Error("Could not determine latest release.");
|
||||||
}
|
}
|
||||||
return latestRelease.tag_name;
|
return latestRelease.tag_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getLatestRelease(
|
|
||||||
octokit: InstanceType<typeof PaginatingOctokit>,
|
|
||||||
) {
|
|
||||||
const { data: latestRelease } = await octokit.rest.repos.getLatestRelease({
|
|
||||||
owner: OWNER,
|
|
||||||
repo: REPO,
|
|
||||||
});
|
|
||||||
return latestRelease;
|
|
||||||
}
|
|
||||||
|
|
||||||
function maxSatisfying(
|
|
||||||
versions: string[],
|
|
||||||
version: string,
|
|
||||||
): string | undefined {
|
|
||||||
const maxSemver = tc.evaluateVersions(versions, version);
|
|
||||||
if (maxSemver !== "") {
|
|
||||||
core.debug(`Found a version that satisfies the semver range: ${maxSemver}`);
|
|
||||||
return maxSemver;
|
|
||||||
}
|
|
||||||
const maxPep440 = pep440.maxSatisfying(versions, version);
|
|
||||||
if (maxPep440 !== null) {
|
|
||||||
core.debug(
|
|
||||||
`Found a version that satisfies the pep440 specifier: ${maxPep440}`,
|
|
||||||
);
|
|
||||||
return maxPep440;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|||||||
+17
-33
@@ -1,12 +1,18 @@
|
|||||||
import * as path from "node:path";
|
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
import * as exec from "@actions/exec";
|
import * as exec from "@actions/exec";
|
||||||
import * as semver from "semver";
|
import * as path from "node:path";
|
||||||
import {
|
import {
|
||||||
downloadVersion,
|
downloadVersion,
|
||||||
resolveVersion,
|
resolveVersion,
|
||||||
tryGetFromToolCache,
|
tryGetFromToolCache,
|
||||||
} from "./download/download-version";
|
} from "./download/download-version";
|
||||||
|
|
||||||
|
import {
|
||||||
|
type Architecture,
|
||||||
|
getArch,
|
||||||
|
getPlatform,
|
||||||
|
type Platform,
|
||||||
|
} from "./utils/platforms";
|
||||||
import {
|
import {
|
||||||
args,
|
args,
|
||||||
checkSum,
|
checkSum,
|
||||||
@@ -15,14 +21,8 @@ import {
|
|||||||
version,
|
version,
|
||||||
versionFile as versionFileInput,
|
versionFile as versionFileInput,
|
||||||
} from "./utils/inputs";
|
} from "./utils/inputs";
|
||||||
import {
|
import { getRuffVersionFromPyproject } from "./utils/pyproject";
|
||||||
type Architecture,
|
import * as fs from "node:fs";
|
||||||
getArch,
|
|
||||||
getPlatform,
|
|
||||||
type Platform,
|
|
||||||
} from "./utils/platforms";
|
|
||||||
import { getRuffVersionFromRequirementsFile } from "./utils/pyproject";
|
|
||||||
import { findPyprojectToml } from "./utils/pyproject-finder";
|
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
const platform = getPlatform();
|
const platform = getPlatform();
|
||||||
@@ -62,11 +62,6 @@ async function setupRuff(
|
|||||||
githubToken: string,
|
githubToken: string,
|
||||||
): Promise<{ ruffDir: string; version: string }> {
|
): Promise<{ ruffDir: string; version: string }> {
|
||||||
const resolvedVersion = await determineVersion();
|
const resolvedVersion = await determineVersion();
|
||||||
if (semver.lt(resolvedVersion, "v0.0.247")) {
|
|
||||||
throw Error(
|
|
||||||
"This action does not support ruff versions older than 0.0.247",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const toolCacheResult = tryGetFromToolCache(arch, resolvedVersion);
|
const toolCacheResult = tryGetFromToolCache(arch, resolvedVersion);
|
||||||
if (toolCacheResult.installedPath) {
|
if (toolCacheResult.installedPath) {
|
||||||
core.info(`Found ruffDir in tool-cache for ${toolCacheResult.version}`);
|
core.info(`Found ruffDir in tool-cache for ${toolCacheResult.version}`);
|
||||||
@@ -98,30 +93,19 @@ async function determineVersion(): Promise<string> {
|
|||||||
return await resolveVersion(version, githubToken);
|
return await resolveVersion(version, githubToken);
|
||||||
}
|
}
|
||||||
if (versionFileInput !== "") {
|
if (versionFileInput !== "") {
|
||||||
const versionFromPyproject =
|
const versionFromPyproject = getRuffVersionFromPyproject(versionFileInput);
|
||||||
getRuffVersionFromRequirementsFile(versionFileInput);
|
|
||||||
if (versionFromPyproject === undefined) {
|
if (versionFromPyproject === undefined) {
|
||||||
core.warning(
|
core.warning(
|
||||||
`Could not parse version from ${versionFileInput}. Using latest version.`,
|
"Could not parse version from supplied pyproject.toml. Using latest version.",
|
||||||
);
|
);
|
||||||
}
|
|
||||||
return await resolveVersion(versionFromPyproject || "latest", githubToken);
|
|
||||||
}
|
|
||||||
const pyProjectPath = findPyprojectToml(
|
|
||||||
src,
|
|
||||||
process.env.GITHUB_WORKSPACE || ".",
|
|
||||||
);
|
|
||||||
if (!pyProjectPath) {
|
|
||||||
core.info(`Could not find pyproject.toml. Using latest version.`);
|
|
||||||
return await resolveVersion("latest", githubToken);
|
return await resolveVersion("latest", githubToken);
|
||||||
}
|
}
|
||||||
const versionFromPyproject =
|
|
||||||
getRuffVersionFromRequirementsFile(pyProjectPath);
|
|
||||||
if (versionFromPyproject === undefined) {
|
|
||||||
core.info(
|
|
||||||
`Could not parse version from ${pyProjectPath}. Using latest version.`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
const pyProjectPath = path.join(src, "pyproject.toml");
|
||||||
|
if (!fs.existsSync(pyProjectPath)) {
|
||||||
|
return await resolveVersion("latest", githubToken);
|
||||||
|
}
|
||||||
|
const versionFromPyproject = getRuffVersionFromPyproject(pyProjectPath);
|
||||||
return await resolveVersion(versionFromPyproject || "latest", githubToken);
|
return await resolveVersion(versionFromPyproject || "latest", githubToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
|
import * as github from "@actions/github";
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
import { Octokit } from "@octokit/core";
|
|
||||||
import { paginateRest } from "@octokit/plugin-paginate-rest";
|
|
||||||
import { restEndpointMethods } from "@octokit/plugin-rest-endpoint-methods";
|
|
||||||
import * as semver from "semver";
|
|
||||||
import { updateChecksums } from "./download/checksum/update-known-checksums";
|
|
||||||
import { OWNER, REPO } from "./utils/constants";
|
|
||||||
|
|
||||||
const PaginatingOctokit = Octokit.plugin(paginateRest, restEndpointMethods);
|
import { OWNER, REPO } from "./utils/constants";
|
||||||
|
import * as semver from "semver";
|
||||||
|
|
||||||
|
import { updateChecksums } from "./download/checksum/update-known-checksums";
|
||||||
|
|
||||||
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 github_token = process.argv.slice(2)[1];
|
||||||
|
|
||||||
const octokit = new PaginatingOctokit({ auth: github_token });
|
const octokit = github.getOctokit(github_token);
|
||||||
|
|
||||||
const response = await octokit.paginate(octokit.rest.repos.listReleases, {
|
const response = await octokit.paginate(octokit.rest.repos.listReleases, {
|
||||||
owner: OWNER,
|
owner: OWNER,
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ export type Architecture = "i686" | "x86_64" | "aarch64";
|
|||||||
export function getArch(): Architecture | undefined {
|
export function getArch(): Architecture | undefined {
|
||||||
const arch = process.arch;
|
const arch = process.arch;
|
||||||
const archMapping: { [key: string]: Architecture } = {
|
const archMapping: { [key: string]: Architecture } = {
|
||||||
arm64: "aarch64",
|
|
||||||
ia32: "i686",
|
ia32: "i686",
|
||||||
x64: "x86_64",
|
x64: "x86_64",
|
||||||
|
arm64: "aarch64",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (arch in archMapping) {
|
if (arch in archMapping) {
|
||||||
@@ -22,8 +22,8 @@ export function getArch(): Architecture | undefined {
|
|||||||
export function getPlatform(): Platform | undefined {
|
export function getPlatform(): Platform | undefined {
|
||||||
const platform = process.platform;
|
const platform = process.platform;
|
||||||
const platformMapping: { [key: string]: Platform } = {
|
const platformMapping: { [key: string]: Platform } = {
|
||||||
darwin: "apple-darwin",
|
|
||||||
linux: "unknown-linux-gnu",
|
linux: "unknown-linux-gnu",
|
||||||
|
darwin: "apple-darwin",
|
||||||
win32: "pc-windows-msvc",
|
win32: "pc-windows-msvc",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
import * as fs from "node:fs";
|
|
||||||
import * as path from "node:path";
|
|
||||||
import * as core from "@actions/core";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search for a pyproject.toml file starting from the given directory
|
|
||||||
* and traversing upwards through parent directories until reaching
|
|
||||||
* the GitHub workspace root.
|
|
||||||
*
|
|
||||||
* @param startDir The directory to start the search from (e.g., the src input)
|
|
||||||
* @param workspaceRoot The GitHub workspace directory (GITHUB_WORKSPACE)
|
|
||||||
* @returns The path to the found pyproject.toml, or undefined if not found
|
|
||||||
*/
|
|
||||||
export function findPyprojectToml(
|
|
||||||
startDir: string,
|
|
||||||
workspaceRoot: string,
|
|
||||||
): string | undefined {
|
|
||||||
let currentDir = path.resolve(startDir);
|
|
||||||
const resolvedWorkspaceRoot = path.resolve(workspaceRoot);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
const pyprojectPath = path.join(currentDir, "pyproject.toml");
|
|
||||||
core.debug(`Checking for ${pyprojectPath}`);
|
|
||||||
|
|
||||||
if (fs.existsSync(pyprojectPath)) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentDir = parentDir;
|
|
||||||
|
|
||||||
// If we've gone past the workspace root, stop searching
|
|
||||||
if (isPathWithinWorkspace(currentDir, resolvedWorkspaceRoot) === false) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a given path is within or equal to the workspace root.
|
|
||||||
*
|
|
||||||
* @param checkPath The path to check
|
|
||||||
* @param workspaceRoot The workspace root directory
|
|
||||||
* @returns true if within or equal to workspace, false if outside, undefined if can't determine
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,188 +0,0 @@
|
|||||||
import * as core from "@actions/core";
|
|
||||||
import { findRuffVersionInSpec } from "./pyproject";
|
|
||||||
|
|
||||||
jest.mock("@actions/core", () => ({
|
|
||||||
info: jest.fn(),
|
|
||||||
warning: jest.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe("findRuffVersionInSpec", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
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(
|
|
||||||
"Found ruff version in requirements file: 0.9.3",
|
|
||||||
);
|
|
||||||
expect(core.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();
|
|
||||||
});
|
|
||||||
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should strip trailing backslash", () => {
|
|
||||||
const result = findRuffVersionInSpec("ruff==0.9.3 \\");
|
|
||||||
expect(result).toBe("0.9.3");
|
|
||||||
expect(core.info).toHaveBeenCalledWith(
|
|
||||||
"Found ruff version in requirements file: 0.9.3",
|
|
||||||
);
|
|
||||||
expect(core.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();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("environment markers", () => {
|
|
||||||
it("should strip python_version environment marker", () => {
|
|
||||||
const result = findRuffVersionInSpec(
|
|
||||||
'ruff>=0.14 ; python_version >= "3.11"',
|
|
||||||
);
|
|
||||||
expect(result).toBe(">=0.14");
|
|
||||||
expect(core.info).toHaveBeenCalledWith(
|
|
||||||
"Found ruff version in requirements file: >=0.14",
|
|
||||||
);
|
|
||||||
expect(core.warning).toHaveBeenCalledWith(
|
|
||||||
"Environment markers are ignored. ruff is a standalone tool that works independently of Python version.",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should strip sys_platform environment marker", () => {
|
|
||||||
const result = findRuffVersionInSpec(
|
|
||||||
"ruff==0.9.3 ; sys_platform == 'linux'",
|
|
||||||
);
|
|
||||||
expect(result).toBe("0.9.3");
|
|
||||||
expect(core.warning).toHaveBeenCalledWith(
|
|
||||||
"Environment markers are ignored. ruff is a standalone tool that works independently of Python version.",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should strip multiple environment markers", () => {
|
|
||||||
const result = findRuffVersionInSpec(
|
|
||||||
'ruff>=0.14 ; python_version >= "3.11" and sys_platform == "linux"',
|
|
||||||
);
|
|
||||||
expect(result).toBe(">=0.14");
|
|
||||||
expect(core.warning).toHaveBeenCalledWith(
|
|
||||||
"Environment markers are ignored. ruff is a standalone tool that works independently of Python version.",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should handle environment markers with multiple constraints", () => {
|
|
||||||
const result = findRuffVersionInSpec(
|
|
||||||
'ruff>=0.14,<1.0 ; python_version >= "3.11"',
|
|
||||||
);
|
|
||||||
expect(result).toBe(">=0.14,<1.0");
|
|
||||||
expect(core.warning).toHaveBeenCalledWith(
|
|
||||||
"Environment markers are ignored. ruff is a standalone tool that works independently of Python version.",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("edge cases", () => {
|
|
||||||
it("should handle whitespace", () => {
|
|
||||||
const result = findRuffVersionInSpec(" ruff >=0.14 ");
|
|
||||||
expect(result).toBe(">=0.14");
|
|
||||||
expect(core.warning).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should handle whitespace with environment markers", () => {
|
|
||||||
const result = findRuffVersionInSpec(
|
|
||||||
" ruff >=0.14 ; python_version >= '3.11' ",
|
|
||||||
);
|
|
||||||
expect(result).toBe(">=0.14");
|
|
||||||
expect(core.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();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return undefined for whitespace only", () => {
|
|
||||||
const result = findRuffVersionInSpec(" ");
|
|
||||||
expect(result).toBeUndefined();
|
|
||||||
expect(core.info).not.toHaveBeenCalled();
|
|
||||||
expect(core.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();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should handle exact example from issue #256", () => {
|
|
||||||
const result = findRuffVersionInSpec(
|
|
||||||
'ruff>=0.14 ; python_version >= "3.11"',
|
|
||||||
);
|
|
||||||
expect(result).toBe(">=0.14");
|
|
||||||
expect(core.info).toHaveBeenCalledWith(
|
|
||||||
"Found ruff version in requirements file: >=0.14",
|
|
||||||
);
|
|
||||||
expect(core.warning).toHaveBeenCalledWith(
|
|
||||||
"Environment markers are ignored. ruff is a standalone tool that works independently of Python version.",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should handle single-quoted environment markers", () => {
|
|
||||||
const result = findRuffVersionInSpec(
|
|
||||||
"ruff>=0.14 ; python_version >= '3.11'",
|
|
||||||
);
|
|
||||||
expect(result).toBe(">=0.14");
|
|
||||||
expect(core.warning).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should handle double-quoted environment markers", () => {
|
|
||||||
const result = findRuffVersionInSpec(
|
|
||||||
'ruff>=0.14 ; python_version >= "3.11"',
|
|
||||||
);
|
|
||||||
expect(result).toBe(">=0.14");
|
|
||||||
expect(core.warning).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
+27
-111
@@ -2,114 +2,7 @@ import * as fs from "node:fs";
|
|||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
import * as toml from "smol-toml";
|
import * as toml from "smol-toml";
|
||||||
|
|
||||||
/**
|
export function getRuffVersionFromPyproject(
|
||||||
* Find ruff version in a dependency specification.
|
|
||||||
* Only handles strings that start with "ruff" (e.g., "ruff==0.9.3").
|
|
||||||
* Returns undefined for non-ruff dependencies.
|
|
||||||
* Strips environment markers (everything after ';').
|
|
||||||
* Strips leading '==' from exact version specifiers (PEP 440) for downstream compatibility.
|
|
||||||
*
|
|
||||||
* @internal This is exported for testing purposes only.
|
|
||||||
*/
|
|
||||||
export function findRuffVersionInSpec(spec: string): string | undefined {
|
|
||||||
const trimmedSpec = spec.trim();
|
|
||||||
|
|
||||||
const fullDepMatch = trimmedSpec.match(/^ruff\s*(.+)$/);
|
|
||||||
let versionSpec: string;
|
|
||||||
if (fullDepMatch) {
|
|
||||||
versionSpec = fullDepMatch[1];
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strip trailing backslash (line continuation)
|
|
||||||
versionSpec = versionSpec.replace(/\\$/, "").trim();
|
|
||||||
|
|
||||||
// Strip environment markers (everything after ';')
|
|
||||||
const match = versionSpec.match(/^([^;]+)(?:;.*)?$/);
|
|
||||||
|
|
||||||
if (match) {
|
|
||||||
let version = match[1].trim();
|
|
||||||
if (version) {
|
|
||||||
// Strip leading '==' from exact version specifiers for compatibility with semver
|
|
||||||
if (version.startsWith("==")) {
|
|
||||||
version = version.slice(2);
|
|
||||||
}
|
|
||||||
if (trimmedSpec.includes(";")) {
|
|
||||||
core.warning(
|
|
||||||
"Environment markers are ignored. ruff is a standalone tool that works independently of Python version.",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
core.info(`Found ruff version in requirements file: ${version}`);
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRuffVersionFromAllDependencies(
|
|
||||||
allDependencies: string[],
|
|
||||||
): string | undefined {
|
|
||||||
return allDependencies
|
|
||||||
.map((dep) => findRuffVersionInSpec(dep))
|
|
||||||
.find((version) => version !== undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Pyproject {
|
|
||||||
project?: {
|
|
||||||
dependencies?: string[];
|
|
||||||
"optional-dependencies"?: Record<string, string[]>;
|
|
||||||
};
|
|
||||||
"dependency-groups"?: Record<string, Array<string | object>>;
|
|
||||||
tool?: {
|
|
||||||
poetry?: {
|
|
||||||
dependencies?: Record<string, string | object>;
|
|
||||||
group?: Record<string, { dependencies: Record<string, string | object> }>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function parsePyproject(pyprojectContent: string): string | undefined {
|
|
||||||
const pyproject: Pyproject = toml.parse(pyprojectContent);
|
|
||||||
const dependencies: string[] = pyproject?.project?.dependencies || [];
|
|
||||||
const optionalDependencies: string[] = Object.values(
|
|
||||||
pyproject?.project?.["optional-dependencies"] || {},
|
|
||||||
).flat();
|
|
||||||
const devDependencies: string[] = Object.values(
|
|
||||||
pyproject?.["dependency-groups"] || {},
|
|
||||||
)
|
|
||||||
.flat()
|
|
||||||
.filter((item: string | object) => typeof item === "string");
|
|
||||||
return (
|
|
||||||
getRuffVersionFromAllDependencies(
|
|
||||||
dependencies.concat(optionalDependencies, devDependencies),
|
|
||||||
) || getRuffVersionFromPoetryGroups(pyproject)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRuffVersionFromPoetryGroups(
|
|
||||||
pyproject: Pyproject,
|
|
||||||
): string | undefined {
|
|
||||||
// Special handling for Poetry until it supports PEP 735
|
|
||||||
// See: <https://github.com/python-poetry/poetry/issues/9751>
|
|
||||||
const poetry = pyproject?.tool?.poetry || {};
|
|
||||||
const poetryGroups = Object.values(poetry.group || {});
|
|
||||||
if (poetry.dependencies) {
|
|
||||||
poetryGroups.unshift({ dependencies: poetry.dependencies });
|
|
||||||
}
|
|
||||||
return poetryGroups
|
|
||||||
.flatMap((group) => Object.entries(group.dependencies))
|
|
||||||
.map(([name, spec]) => {
|
|
||||||
if (typeof spec === "string") {
|
|
||||||
return findRuffVersionInSpec(`${name} ${spec}`);
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
})
|
|
||||||
.find((version) => version !== undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRuffVersionFromRequirementsFile(
|
|
||||||
filePath: string,
|
filePath: string,
|
||||||
): string | undefined {
|
): string | undefined {
|
||||||
if (!fs.existsSync(filePath)) {
|
if (!fs.existsSync(filePath)) {
|
||||||
@@ -117,14 +10,37 @@ export function getRuffVersionFromRequirementsFile(
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const pyprojectContent = fs.readFileSync(filePath, "utf-8");
|
const pyprojectContent = fs.readFileSync(filePath, "utf-8");
|
||||||
if (filePath.endsWith(".txt")) {
|
let pyproject:
|
||||||
return getRuffVersionFromAllDependencies(pyprojectContent.split("\n"));
|
| {
|
||||||
|
project?: { dependencies?: string[] };
|
||||||
|
"dependency-groups"?: { dev?: string[] };
|
||||||
}
|
}
|
||||||
|
| undefined;
|
||||||
try {
|
try {
|
||||||
return parsePyproject(pyprojectContent);
|
pyproject = toml.parse(pyprojectContent);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const message = (err as Error).message;
|
const message = (err as Error).message;
|
||||||
core.warning(`Error while parsing ${filePath}: ${message}`);
|
core.warning(`Error while parsing ${filePath}: ${message}`);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const dependencies: string[] = pyproject?.project?.dependencies || [];
|
||||||
|
const devDependencies: string[] = pyproject?.["dependency-groups"]?.dev || [];
|
||||||
|
|
||||||
|
const ruffVersionDefinition =
|
||||||
|
dependencies.find((dep: string) => dep.startsWith("ruff")) ||
|
||||||
|
devDependencies.find((dep: string) => dep.startsWith("ruff"));
|
||||||
|
|
||||||
|
if (ruffVersionDefinition) {
|
||||||
|
const ruffVersion = ruffVersionDefinition
|
||||||
|
.match(/^ruff([^A-Z0-9._-]+.*)$/)?.[1]
|
||||||
|
.trim();
|
||||||
|
if (ruffVersion?.startsWith("==")) {
|
||||||
|
return ruffVersion.slice(2);
|
||||||
|
}
|
||||||
|
core.info(`Found ruff version in pyproject.toml: ${ruffVersion}`);
|
||||||
|
return ruffVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -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'. */,
|
"target": "ES2022" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
|
||||||
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
|
"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. */,
|
"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. */,
|
"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. */,
|
"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'. */
|
"noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
|
||||||
|
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules", "**/*.test.ts"]
|
"exclude": ["node_modules", "**/*.test.ts"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user