Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/ci/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,15 @@ Checkout, Python setup, Node setup, and retry actions use Node 24-based releases
(`checkout@v6`, `setup-python@v6`, `setup-node@v6`, `retry@v4`). The action
runtime is separate from the Python and Node versions installed for tests.

Remote action references are pinned to full commit SHAs with version comments,
including the download and workflow retry steps. When updating an action,
verify its SHA against the upstream repository and update the version comment.
The offline policy checks reject mutable action references. Dependabot checks
GitHub Actions weekly and groups their version updates; its seven-day cooldown
filters newly published versions, rather than setting the interval between PRs.
Its explicit `ci` commit prefix and dependency scope keep generated PR titles
aligned with the repository's conventional-commit title checks.

Node 22 satisfies commitlint's Node >=22.12 requirement. The root `package.json`
and `package-lock.json` pin the title tooling and its transitive dependencies;
CI uses `npm ci --ignore-scripts` and `npx --no-install`.
Expand Down
14 changes: 14 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
commit-message:
prefix: "ci"
include: "scope"
groups:
github-actions:
patterns: ["*"]
schedule:
interval: "weekly"
cooldown:
default-days: 7
4 changes: 2 additions & 2 deletions .github/workflows/lint_title.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ jobs:
steps:
# This step is necessary because the lint title uses the .commitlintrc.js file in the project root directory.
- name: Checkout Repository
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6

- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: '22'

Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
steps:
- name: Release please
id: release_please
uses: googleapis/release-please-action@v4
uses: googleapis/release-please-action@5c625bfb5d1ff62eadeeb3772007f7f66fdcf071 # v4.4.1
with:
token: ${{ secrets.PAT }}
release-type: simple
Expand All @@ -30,20 +30,20 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
if: needs.release.outputs.release_created == 'true'
with:
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
if: needs.release.outputs.release_created == 'true'
uses: actions/setup-python@v4
uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4.9.1
with:
python-version: ${{ matrix.python-version }}

- name: Build wheel on Linux
if: needs.release.outputs.release_created == 'true'
uses: RalfG/python-wheels-manylinux-build@v0.7.1-manylinux2014_x86_64
uses: RalfG/python-wheels-manylinux-build@ff8504699f7a33a08d3ff85b3c6d4e8f0e70462b # v0.7.1-manylinux2014_x86_64
with:
python-versions: 'cp38-cp38 cp39-cp39 cp310-cp310 cp311-cp311 cp312-cp312'
build-requirements: 'numpy cython'
Expand Down Expand Up @@ -76,14 +76,14 @@ jobs:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
if: needs.release.outputs.release_created == 'true'
with:
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
if: needs.release.outputs.release_created == 'true'
uses: actions/setup-python@v4
uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4.9.1
with:
python-version: ${{ matrix.python-version }}

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/stale.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/stale@v3
- uses: actions/stale@98ed4cb500039dbcccf4bd9bedada4d0187f2757 # v3.0.19
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue is stale because it has been open for three months with no activity. Remove the stale label or comment on the issue otherwise this will be closed in 5 days'
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/test_qlib_from_pip.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ jobs:

steps:
- name: Test qlib from pip
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: ${{ matrix.python-version }}

Expand All @@ -61,7 +61,7 @@ jobs:
python -m pip install --no-binary=:all: lightgbm

- name: Downloads dependencies data
uses: nick-fields/retry@v4
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4
with:
timeout_minutes: 15
max_attempts: 3
Expand All @@ -73,7 +73,7 @@ jobs:
python -m qlib.cli.data qlib_data --target_dir ~/.qlib/qlib_data/cn_data --region cn --delete_old False

- name: Test workflow by config
uses: nick-fields/retry@v4
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4
with:
timeout_minutes: 30
max_attempts: 3
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/test_qlib_from_source.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ jobs:

steps:
- name: Test qlib from source
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: ${{ matrix.python-version }}

Expand Down Expand Up @@ -105,7 +105,7 @@ jobs:
make nbqa

- name: Test data downloads
uses: nick-fields/retry@v4
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4
with:
timeout_minutes: 15
max_attempts: 3
Expand All @@ -121,7 +121,7 @@ jobs:
make nbconvert

- name: Test workflow by config (install from source)
uses: nick-fields/retry@v4
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4
with:
timeout_minutes: 30
max_attempts: 3
Expand All @@ -134,7 +134,7 @@ jobs:

- name: Unit tests with Pytest (MacOS)
if: ${{ matrix.os == 'macos-14' || matrix.os == 'macos-15' }}
uses: nick-fields/retry@v4
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4
with:
timeout_minutes: 60
max_attempts: 3
Expand All @@ -150,7 +150,7 @@ jobs:

- name: Unit tests with Pytest (Ubuntu and Windows)
if: ${{ matrix.os != 'macos-13' && matrix.os != 'macos-14' && matrix.os != 'macos-15' }}
uses: nick-fields/retry@v4
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4
with:
timeout_minutes: 60
max_attempts: 3
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/test_qlib_from_source_slow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ jobs:

steps:
- name: Test qlib from source slow
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: ${{ matrix.python-version }}

Expand Down Expand Up @@ -75,7 +75,7 @@ jobs:
run: python -c "import cvxpy, osqp; print('CVXPY', cvxpy.__version__, 'OSQP', osqp.__version__)"

- name: Downloads dependencies data
uses: nick-fields/retry@v4
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4
with:
timeout_minutes: 15
max_attempts: 3
Expand All @@ -84,7 +84,7 @@ jobs:
command: python scripts/get_data.py qlib_data --name qlib_data_simple --target_dir ~/.qlib/qlib_data/cn_data --interval 1d --region cn --delete_old False

- name: Unit tests with Pytest
uses: nick-fields/retry@v4
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4
with:
timeout_minutes: 240
max_attempts: 3
Expand Down
22 changes: 22 additions & 0 deletions tests/test_ci_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,28 @@ def test_consistency_and_native_import_are_checked(self):
self.assertEqual(steps[-1]["name"], "Report installed dependencies")
self.assertEqual(steps[-1]["if"], "always()")

def test_dependabot_action_updates_use_ci_commit_prefix(self):
config = yaml.safe_load((ROOT / ".github/dependabot.yml").read_text(encoding="utf-8"))
updates = [entry for entry in config["updates"] if entry["package-ecosystem"] == "github-actions"]
self.assertTrue(updates)
for entry in updates:
with self.subTest(directory=entry["directory"]):
self.assertEqual(entry["commit-message"], {"prefix": "ci", "include": "scope"})

def test_remote_actions_use_full_commit_shas(self):
paths = sorted((ROOT / ".github/workflows").glob("*.yml"))
paths += sorted((ROOT / ".github/workflows").glob("*.yaml"))
self.assertTrue(paths)
for path in paths:
workflow = yaml.safe_load(path.read_text(encoding="utf-8"))
for job in workflow["jobs"].values():
for entry in [job] + job.get("steps", []):
reference = entry.get("uses", "")
if not reference or reference.startswith("./"):
continue
with self.subTest(workflow=path.name, action=reference):
self.assertRegex(reference, r"^[\w.-]+/[\w./-]+@[0-9a-f]{40}$")

def test_title_lint_uses_a_lockfile_and_no_dynamic_download(self):
workflow = yaml.safe_load((ROOT / ".github/workflows/lint_title.yml").read_text(encoding="utf-8"))
steps = workflow["jobs"]["lint-title"]["steps"]
Expand Down
Loading