Cache python installs (#621)
Some checks failed
CodeQL / Analyze (TypeScript) (push) Failing after 2s
test / lint (push) Failing after 2s
test / test-default-version (ubuntu-latest) (push) Failing after 2s
test / test-uv-no-modify-path (push) Failing after 2s
test / test-specific-version (map[expected-version:0.3.0 version-input:0.3.0]) (push) Failing after 2s
test / test-specific-version (map[expected-version:0.3.2 version-input:0.3.2]) (push) Failing after 2s
test / test-specific-version (map[expected-version:0.3.5 version-input:0.3.x]) (push) Failing after 2s
test / test-specific-version (map[expected-version:0.3.5 version-input:0.3]) (push) Failing after 2s
test / test-specific-version (map[expected-version:0.4.30 version-input:>=0.4.25,<0.5]) (push) Failing after 2s
test / test-latest-version (>=0.8) (push) Failing after 1s
test / test-latest-version (latest) (push) Failing after 2s
test / test-from-working-directory-version (map[expected-version:0.5.14 working-directory:__tests__/fixtures/pyproject-toml-project]) (push) Failing after 2s
test / test-from-working-directory-version (map[expected-version:0.5.15 working-directory:__tests__/fixtures/uv-toml-project]) (push) Failing after 2s
test / test-version-file-version (map[expected-version:0.5.15 version-file:__tests__/fixtures/.tool-versions]) (push) Failing after 2s
test / test-version-file-version (map[expected-version:0.6.17 version-file:__tests__/fixtures/uv-in-requirements-txt-project/requirements.txt]) (push) Failing after 2s
test / test-version-file-version (map[expected-version:0.8.3 version-file:__tests__/fixtures/uv-in-requirements-hash-txt-project/requirements.txt]) (push) Failing after 2s
test / test-malformed-pyproject-file-fallback (push) Failing after 2s
test / test-checksum (map[checksum:4d9279ad5ca596b1e2d703901d508430eb07564dc4d8837de9e2fca9c90f8ecd os:ubuntu-latest]) (push) Failing after 1s
test / test-with-explicit-token (push) Failing after 1s
test / test-uvx (push) Failing after 1s
test / test-tool-install (ubuntu-latest) (push) Failing after 2s
test / test-python-version (ubuntu-latest) (push) Failing after 2s
test / test-activate-environment (ubuntu-latest) (push) Failing after 2s
test / test-setup-cache (auto, ubuntu-latest) (push) Failing after 1s
test / test-setup-cache (false, ubuntu-latest) (push) Failing after 2s
test / test-setup-cache (true, ubuntu-latest) (push) Failing after 2s
test / test-musl (push) Failing after 6s
test / test-restore-cache-requirements-txt (push) Has been skipped
test / test-setup-cache-dependency-glob (push) Failing after 2s
test / test-setup-cache-requirements-txt (push) Failing after 2s
test / test-restore-cache-dependency-glob (push) Has been skipped
test / test-setup-cache-save-cache-false (push) Failing after 2s
test / test-restore-cache-save-cache-false (push) Has been skipped
test / test-setup-cache-restore-cache-false (push) Failing after 3s
test / test-cache-local (map[expected-cache-dir:/home/runner/work/_temp/setup-uv-cache os:ubuntu-latest]) (push) Failing after 3s
test / test-restore-cache-restore-cache-false (push) Has been skipped
test / test-cache-local-cache-disabled (push) Failing after 5s
test / test-no-python-version (push) Failing after 5s
test / test-custom-manifest-file (push) Failing after 5s
test / test-absolute-path (push) Failing after 5s
test / test-relative-path (push) Failing after 5s
test / test-cache-prune-force (push) Failing after 5s
test / test-cache-dir-from-file (push) Failing after 5s
test / test-restore-python-installs (push) Has been skipped
test / test-cache-python-installs (push) Failing after 5s
Release Drafter / ✏️ Draft release (push) Has been cancelled
test / test-tool-install (macos-14) (push) Has been cancelled
test / test-tool-install (macos-latest) (push) Has been cancelled
test / test-tool-install (windows-latest) (push) Has been cancelled
test / test-default-version (macos-14) (push) Has been cancelled
test / test-default-version (macos-latest) (push) Has been cancelled
test / test-default-version (windows-latest) (push) Has been cancelled
test / test-tilde-expansion-tool-dirs (push) Has been cancelled
test / test-checksum (map[checksum:a70cbfbf3bb5c08b2f84963b4f12c94e08fbb2468ba418a3bfe1066fbe9e7218 os:macos-latest]) (push) Has been cancelled
test / test-python-version (macos-latest) (push) Has been cancelled
test / test-python-version (windows-latest) (push) Has been cancelled
test / test-activate-environment (macos-latest) (push) Has been cancelled
test / test-activate-environment (windows-latest) (push) Has been cancelled
test / test-setup-cache (auto, selfhosted-ubuntu-arm64) (push) Has been cancelled
test / test-setup-cache (auto, windows-latest) (push) Has been cancelled
test / test-setup-cache (false, selfhosted-ubuntu-arm64) (push) Has been cancelled
test / test-setup-cache (false, windows-latest) (push) Has been cancelled
test / test-setup-cache (true, selfhosted-ubuntu-arm64) (push) Has been cancelled
test / test-setup-cache (true, windows-latest) (push) Has been cancelled
test / test-cache-local (map[expected-cache-dir:/home/ubuntu/.cache/uv os:selfhosted-ubuntu-arm64]) (push) Has been cancelled
test / test-cache-local (map[expected-cache-dir:D:\a\_temp\setup-uv-cache os:windows-latest]) (push) Has been cancelled
test / test-setup-cache-local (push) Has been cancelled
test / test-tilde-expansion-cache-local-path (push) Has been cancelled
test / test-tilde-expansion-cache-dependency-glob (push) Has been cancelled
test / test-restore-cache (true, ubuntu-latest) (push) Has been cancelled
test / test-restore-cache (true, windows-latest) (push) Has been cancelled
test / test-restore-cache (false, selfhosted-ubuntu-arm64) (push) Has been cancelled
test / test-restore-cache (false, ubuntu-latest) (push) Has been cancelled
test / test-restore-cache (false, windows-latest) (push) Has been cancelled
test / test-restore-cache (true, selfhosted-ubuntu-arm64) (push) Has been cancelled
test / test-restore-cache (auto, selfhosted-ubuntu-arm64) (push) Has been cancelled
test / test-restore-cache (auto, ubuntu-latest) (push) Has been cancelled
test / test-restore-cache (auto, windows-latest) (push) Has been cancelled
test / test-restore-cache-local (push) Has been cancelled
test / cleanup-tilde-expansion-tests (push) Has been cancelled
test / all-tests-passed (push) Has been cancelled

This pull request introduces support for caching Python installs in the
GitHub Action, allowing users to cache not only dependencies but also
the Python interpreter itself.

This works by setting the `UV_PYTHON_INSTALL_DIR` to a subdirectory of
the dependency cache path so that Python installs are directed there.

Fixes #135

---------

Co-authored-by: Kevin Stillhammer <kevin.stillhammer@gmail.com>
This commit is contained in:
Merlin
2025-10-09 16:47:24 -04:00
committed by GitHub
parent 3495667518
commit 6d2eb15b49
8 changed files with 197 additions and 23 deletions

View File

@@ -25,7 +25,7 @@ jobs:
with:
persist-credentials: false
- name: Actionlint
uses: eifinger/actionlint-action@23c85443d840cd73bbecb9cddfc933cc21649a38 # v1.9.1
uses: eifinger/actionlint-action@23c85443d840cd73bbecb9cddfc933cc21649a38 # v1.9.1
- name: Run zizmor
uses: zizmorcore/zizmor-action@e673c3917a1aef3c65c972347ed84ccd013ecda4 # v0.2.0
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
@@ -269,13 +269,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
[
ubuntu-latest,
macos-latest,
macos-14,
windows-latest,
]
os: [ubuntu-latest, macos-latest, macos-14, windows-latest]
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
@@ -334,7 +328,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
@@ -371,8 +365,8 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
enable-cache: [ "true", "false", "auto" ]
os: [ "ubuntu-latest", "selfhosted-ubuntu-arm64", "windows-latest" ]
enable-cache: ["true", "false", "auto"]
os: ["ubuntu-latest", "selfhosted-ubuntu-arm64", "windows-latest"]
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
@@ -389,8 +383,8 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
enable-cache: [ "true", "false", "auto" ]
os: [ "ubuntu-latest", "selfhosted-ubuntu-arm64", "windows-latest" ]
enable-cache: ["true", "false", "auto"]
os: ["ubuntu-latest", "selfhosted-ubuntu-arm64", "windows-latest"]
needs: test-setup-cache
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
@@ -836,6 +830,68 @@ jobs:
exit 1
fi
test-cache-python-installs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: Verify Python install dir is not populated
run: |
if [ -d ~/.local/share/uv/python ]; then
echo "Python install dir should not exist"
exit 1
fi
- name: Setup uv with cache
uses: ./
with:
enable-cache: true
cache-python: true
cache-suffix: ${{ github.run_id }}-${{ github.run_attempt }}-test-cache-python-installs
- run: uv sync --managed-python
working-directory: __tests__/fixtures/uv-project
- name: Verify Python install dir exists
run: |
if [ ! -d ~/.local/share/uv/python ]; then
echo "Python install dir should exist"
exit 1
fi
test-restore-python-installs:
runs-on: ubuntu-latest
needs: test-cache-python-installs
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: Verify Python install dir does not exist
run: |
if [ -d ~/.local/share/uv/python ]; then
echo "Python install dir should not exist"
exit 1
fi
- name: Restore with cache
id: restore
uses: ./
with:
enable-cache: true
cache-python: true
cache-suffix: ${{ github.run_id }}-${{ github.run_attempt }}-test-cache-python-installs
- name: Verify Python install dir exists
run: |
if [ ! -d ~/.local/share/uv/python ]; then
echo "Python install dir should exist"
exit 1
fi
- name: Cache was hit
run: |
if [ "$CACHE_HIT" != "true" ]; then
exit 1
fi
env:
CACHE_HIT: ${{ steps.restore.outputs.cache-hit }}
- run: uv sync --managed-python
working-directory: __tests__/fixtures/uv-project
all-tests-passed:
runs-on: ubuntu-latest
needs:
@@ -878,6 +934,8 @@ jobs:
- test-relative-path
- test-cache-prune-force
- test-cache-dir-from-file
- test-cache-python-installs
- test-restore-python-installs
if: always()
steps:
- name: All tests passed

View File

@@ -26,6 +26,7 @@ Set up your GitHub Actions workflow with a specific version of [uv](https://docs
- [Save cache](#save-cache)
- [Local cache path](#local-cache-path)
- [Disable cache pruning](#disable-cache-pruning)
- [Cache Python installs](#cache-python-installs)
- [Ignore nothing to cache](#ignore-nothing-to-cache)
- [GitHub authentication token](#github-authentication-token)
- [UV_TOOL_DIR](#uv_tool_dir)
@@ -355,6 +356,20 @@ input.
prune-cache: false
```
### Cache Python installs
By default, the Python install dir (`uv python dir` / `UV_PYTHON_INSTALL_DIR`) is not cached,
for the same reason that the dependency cache is pruned.
If you want to cache Python installs along with your dependencies, set the `cache-python` input to `true`.
```yaml
- name: Cache Python installs
uses: astral-sh/setup-uv@v6
with:
enable-cache: true
cache-python: true
```
### Ignore nothing to cache
By default, the action will fail if caching is enabled but there is nothing to upload (the uv cache directory does not exist).

View File

@@ -56,6 +56,9 @@ inputs:
prune-cache:
description: "Prune cache before saving."
default: "true"
cache-python:
description: "Upload managed Python installations to the Github Actions cache."
default: "false"
ignore-nothing-to-cache:
description: "Ignore when nothing is found to cache."
default: "false"

40
dist/save-cache/index.js generated vendored
View File

@@ -90593,8 +90593,12 @@ async function restoreCache() {
}
let matchedKey;
core.info(`Trying to restore uv cache from GitHub Actions cache with key: ${cacheKey}`);
const cachePaths = [inputs_1.cacheLocalPath];
if (inputs_1.cachePython) {
cachePaths.push(await (0, inputs_1.getUvPythonDir)());
}
try {
matchedKey = await cache.restoreCache([inputs_1.cacheLocalPath], cacheKey);
matchedKey = await cache.restoreCache(cachePaths, cacheKey);
}
catch (err) {
const message = err.message;
@@ -90620,7 +90624,8 @@ async function computeKeys() {
const pythonVersion = await getPythonVersion();
const platform = await (0, platforms_1.getPlatform)();
const pruned = inputs_1.pruneCache ? "-pruned" : "";
return `setup-uv-${CACHE_VERSION}-${(0, platforms_1.getArch)()}-${platform}-${pythonVersion}${pruned}${cacheDependencyPathHash}${suffix}`;
const python = inputs_1.cachePython ? "-py" : "";
return `setup-uv-${CACHE_VERSION}-${(0, platforms_1.getArch)()}-${platform}-${pythonVersion}${pruned}${python}${cacheDependencyPathHash}${suffix}`;
}
async function getPythonVersion() {
if (inputs_1.pythonVersion !== "") {
@@ -90844,8 +90849,18 @@ async function saveCache() {
if (!fs.existsSync(actualCachePath) && !inputs_1.ignoreNothingToCache) {
throw new Error(`Cache path ${actualCachePath} does not exist on disk. This likely indicates that there are no dependencies to cache. Consider disabling the cache input if it is not needed.`);
}
const cachePaths = [actualCachePath];
if (inputs_1.cachePython) {
const pythonDir = await (0, inputs_1.getUvPythonDir)();
core.info(`Including Python cache path: ${pythonDir}`);
if (!fs.existsSync(pythonDir) && !inputs_1.ignoreNothingToCache) {
throw new Error(`Python cache path ${pythonDir} does not exist on disk. This likely indicates that there are no dependencies to cache. Consider disabling the cache input if it is not needed.`);
}
cachePaths.push(pythonDir);
}
core.info(`Final cache paths: ${cachePaths.join(", ")}`);
try {
await cache.saveCache([actualCachePath], cacheKey);
await cache.saveCache(cachePaths, cacheKey);
core.info(`cache saved with the key: ${cacheKey}`);
}
catch (e) {
@@ -90996,9 +91011,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.addProblemMatchers = exports.manifestFile = exports.githubToken = exports.toolDir = exports.toolBinDir = exports.ignoreEmptyWorkdir = exports.ignoreNothingToCache = exports.pruneCache = exports.cacheDependencyGlob = exports.cacheLocalPath = exports.cacheSuffix = exports.saveCache = exports.restoreCache = exports.enableCache = exports.checkSum = exports.activateEnvironment = exports.pythonVersion = exports.versionFile = exports.version = exports.workingDirectory = void 0;
exports.addProblemMatchers = exports.manifestFile = exports.githubToken = exports.toolDir = exports.toolBinDir = exports.ignoreEmptyWorkdir = exports.ignoreNothingToCache = exports.cachePython = exports.pruneCache = exports.cacheDependencyGlob = exports.cacheLocalPath = exports.cacheSuffix = exports.saveCache = exports.restoreCache = exports.enableCache = exports.checkSum = exports.activateEnvironment = exports.pythonVersion = exports.versionFile = exports.version = exports.workingDirectory = void 0;
exports.getUvPythonDir = getUvPythonDir;
const node_path_1 = __importDefault(__nccwpck_require__(6760));
const core = __importStar(__nccwpck_require__(7484));
const exec = __importStar(__nccwpck_require__(5236));
const config_file_1 = __nccwpck_require__(5465);
exports.workingDirectory = core.getInput("working-directory");
exports.version = core.getInput("version");
@@ -91013,6 +91030,7 @@ exports.cacheSuffix = core.getInput("cache-suffix") || "";
exports.cacheLocalPath = getCacheLocalPath();
exports.cacheDependencyGlob = getCacheDependencyGlob();
exports.pruneCache = core.getInput("prune-cache") === "true";
exports.cachePython = core.getInput("cache-python") === "true";
exports.ignoreNothingToCache = core.getInput("ignore-nothing-to-cache") === "true";
exports.ignoreEmptyWorkdir = core.getInput("ignore-empty-workdir") === "true";
exports.toolBinDir = getToolBinDir();
@@ -91106,6 +91124,20 @@ function getCacheDirFromConfig() {
}
return undefined;
}
async function getUvPythonDir() {
if (process.env.UV_PYTHON_INSTALL_DIR !== undefined) {
core.info(`Using UV_PYTHON_INSTALL_DIR from environment: ${process.env.UV_PYTHON_INSTALL_DIR}`);
return process.env.UV_PYTHON_INSTALL_DIR;
}
core.info("Determining uv python dir using `uv python dir`...");
const result = await exec.getExecOutput("uv", ["python", "dir"]);
if (result.exitCode !== 0) {
throw new Error(`Failed to get uv python dir: ${result.stderr || result.stdout}`);
}
const dir = result.stdout.trim();
core.info(`Determined uv python dir: ${dir}`);
return dir;
}
function getCacheDependencyGlob() {
const cacheDependencyGlobInput = core.getInput("cache-dependency-glob");
if (cacheDependencyGlobInput !== "") {

28
dist/setup/index.js generated vendored
View File

@@ -125151,8 +125151,12 @@ async function restoreCache() {
}
let matchedKey;
core.info(`Trying to restore uv cache from GitHub Actions cache with key: ${cacheKey}`);
const cachePaths = [inputs_1.cacheLocalPath];
if (inputs_1.cachePython) {
cachePaths.push(await (0, inputs_1.getUvPythonDir)());
}
try {
matchedKey = await cache.restoreCache([inputs_1.cacheLocalPath], cacheKey);
matchedKey = await cache.restoreCache(cachePaths, cacheKey);
}
catch (err) {
const message = err.message;
@@ -125178,7 +125182,8 @@ async function computeKeys() {
const pythonVersion = await getPythonVersion();
const platform = await (0, platforms_1.getPlatform)();
const pruned = inputs_1.pruneCache ? "-pruned" : "";
return `setup-uv-${CACHE_VERSION}-${(0, platforms_1.getArch)()}-${platform}-${pythonVersion}${pruned}${cacheDependencyPathHash}${suffix}`;
const python = inputs_1.cachePython ? "-py" : "";
return `setup-uv-${CACHE_VERSION}-${(0, platforms_1.getArch)()}-${platform}-${pythonVersion}${pruned}${python}${cacheDependencyPathHash}${suffix}`;
}
async function getPythonVersion() {
if (inputs_1.pythonVersion !== "") {
@@ -129708,9 +129713,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.addProblemMatchers = exports.manifestFile = exports.githubToken = exports.toolDir = exports.toolBinDir = exports.ignoreEmptyWorkdir = exports.ignoreNothingToCache = exports.pruneCache = exports.cacheDependencyGlob = exports.cacheLocalPath = exports.cacheSuffix = exports.saveCache = exports.restoreCache = exports.enableCache = exports.checkSum = exports.activateEnvironment = exports.pythonVersion = exports.versionFile = exports.version = exports.workingDirectory = void 0;
exports.addProblemMatchers = exports.manifestFile = exports.githubToken = exports.toolDir = exports.toolBinDir = exports.ignoreEmptyWorkdir = exports.ignoreNothingToCache = exports.cachePython = exports.pruneCache = exports.cacheDependencyGlob = exports.cacheLocalPath = exports.cacheSuffix = exports.saveCache = exports.restoreCache = exports.enableCache = exports.checkSum = exports.activateEnvironment = exports.pythonVersion = exports.versionFile = exports.version = exports.workingDirectory = void 0;
exports.getUvPythonDir = getUvPythonDir;
const node_path_1 = __importDefault(__nccwpck_require__(76760));
const core = __importStar(__nccwpck_require__(37484));
const exec = __importStar(__nccwpck_require__(95236));
const config_file_1 = __nccwpck_require__(27846);
exports.workingDirectory = core.getInput("working-directory");
exports.version = core.getInput("version");
@@ -129725,6 +129732,7 @@ exports.cacheSuffix = core.getInput("cache-suffix") || "";
exports.cacheLocalPath = getCacheLocalPath();
exports.cacheDependencyGlob = getCacheDependencyGlob();
exports.pruneCache = core.getInput("prune-cache") === "true";
exports.cachePython = core.getInput("cache-python") === "true";
exports.ignoreNothingToCache = core.getInput("ignore-nothing-to-cache") === "true";
exports.ignoreEmptyWorkdir = core.getInput("ignore-empty-workdir") === "true";
exports.toolBinDir = getToolBinDir();
@@ -129818,6 +129826,20 @@ function getCacheDirFromConfig() {
}
return undefined;
}
async function getUvPythonDir() {
if (process.env.UV_PYTHON_INSTALL_DIR !== undefined) {
core.info(`Using UV_PYTHON_INSTALL_DIR from environment: ${process.env.UV_PYTHON_INSTALL_DIR}`);
return process.env.UV_PYTHON_INSTALL_DIR;
}
core.info("Determining uv python dir using `uv python dir`...");
const result = await exec.getExecOutput("uv", ["python", "dir"]);
if (result.exitCode !== 0) {
throw new Error(`Failed to get uv python dir: ${result.stderr || result.stdout}`);
}
const dir = result.stdout.trim();
core.info(`Determined uv python dir: ${dir}`);
return dir;
}
function getCacheDependencyGlob() {
const cacheDependencyGlobInput = core.getInput("cache-dependency-glob");
if (cacheDependencyGlobInput !== "") {

View File

@@ -5,7 +5,9 @@ import { hashFiles } from "../hash/hash-files";
import {
cacheDependencyGlob,
cacheLocalPath,
cachePython,
cacheSuffix,
getUvPythonDir,
pruneCache,
pythonVersion as pythonVersionInput,
restoreCache as shouldRestoreCache,
@@ -30,8 +32,12 @@ export async function restoreCache(): Promise<void> {
core.info(
`Trying to restore uv cache from GitHub Actions cache with key: ${cacheKey}`,
);
const cachePaths = [cacheLocalPath];
if (cachePython) {
cachePaths.push(await getUvPythonDir());
}
try {
matchedKey = await cache.restoreCache([cacheLocalPath], cacheKey);
matchedKey = await cache.restoreCache(cachePaths, cacheKey);
} catch (err) {
const message = (err as Error).message;
core.warning(message);
@@ -62,7 +68,8 @@ async function computeKeys(): Promise<string> {
const pythonVersion = await getPythonVersion();
const platform = await getPlatform();
const pruned = pruneCache ? "-pruned" : "";
return `setup-uv-${CACHE_VERSION}-${getArch()}-${platform}-${pythonVersion}${pruned}${cacheDependencyPathHash}${suffix}`;
const python = cachePython ? "-py" : "";
return `setup-uv-${CACHE_VERSION}-${getArch()}-${platform}-${pythonVersion}${pruned}${python}${cacheDependencyPathHash}${suffix}`;
}
async function getPythonVersion(): Promise<string> {

View File

@@ -10,7 +10,9 @@ import {
import { STATE_UV_PATH, STATE_UV_VERSION } from "./utils/constants";
import {
cacheLocalPath,
cachePython,
enableCache,
getUvPythonDir,
ignoreNothingToCache,
pruneCache as shouldPruneCache,
saveCache as shouldSaveCache,
@@ -68,8 +70,22 @@ async function saveCache(): Promise<void> {
`Cache path ${actualCachePath} does not exist on disk. This likely indicates that there are no dependencies to cache. Consider disabling the cache input if it is not needed.`,
);
}
const cachePaths = [actualCachePath];
if (cachePython) {
const pythonDir = await getUvPythonDir();
core.info(`Including Python cache path: ${pythonDir}`);
if (!fs.existsSync(pythonDir) && !ignoreNothingToCache) {
throw new Error(
`Python cache path ${pythonDir} does not exist on disk. This likely indicates that there are no dependencies to cache. Consider disabling the cache input if it is not needed.`,
);
}
cachePaths.push(pythonDir);
}
core.info(`Final cache paths: ${cachePaths.join(", ")}`);
try {
await cache.saveCache([actualCachePath], cacheKey);
await cache.saveCache(cachePaths, cacheKey);
core.info(`cache saved with the key: ${cacheKey}`);
} catch (e) {
if (

View File

@@ -1,5 +1,6 @@
import path from "node:path";
import * as core from "@actions/core";
import * as exec from "@actions/exec";
import { getConfigValueFromTomlFile } from "./config-file";
export const workingDirectory = core.getInput("working-directory");
@@ -15,6 +16,7 @@ export const cacheSuffix = core.getInput("cache-suffix") || "";
export const cacheLocalPath = getCacheLocalPath();
export const cacheDependencyGlob = getCacheDependencyGlob();
export const pruneCache = core.getInput("prune-cache") === "true";
export const cachePython = core.getInput("cache-python") === "true";
export const ignoreNothingToCache =
core.getInput("ignore-nothing-to-cache") === "true";
export const ignoreEmptyWorkdir =
@@ -123,6 +125,25 @@ function getCacheDirFromConfig(): string | undefined {
return undefined;
}
export async function getUvPythonDir(): Promise<string> {
if (process.env.UV_PYTHON_INSTALL_DIR !== undefined) {
core.info(
`Using UV_PYTHON_INSTALL_DIR from environment: ${process.env.UV_PYTHON_INSTALL_DIR}`,
);
return process.env.UV_PYTHON_INSTALL_DIR;
}
core.info("Determining uv python dir using `uv python dir`...");
const result = await exec.getExecOutput("uv", ["python", "dir"]);
if (result.exitCode !== 0) {
throw new Error(
`Failed to get uv python dir: ${result.stderr || result.stdout}`,
);
}
const dir = result.stdout.trim();
core.info(`Determined uv python dir: ${dir}`);
return dir;
}
function getCacheDependencyGlob(): string {
const cacheDependencyGlobInput = core.getInput("cache-dependency-glob");
if (cacheDependencyGlobInput !== "") {