mirror of
https://github.com/astral-sh/setup-uv.git
synced 2026-03-13 21:25:17 +00:00
Compare commits
76 Commits
v7.1.3
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
107457289a | ||
|
|
e06108dd0a | ||
|
|
0f6ec07aaf | ||
|
|
821e5c9815 | ||
|
|
6ee6290f1c | ||
|
|
9f332a133a | ||
|
|
0acf9708ce | ||
|
|
fe3617d6e9 | ||
|
|
2ff70eebcc | ||
|
|
5ba8a7e5d0 | ||
|
|
4bc8fabc0c | ||
|
|
950b623541 | ||
|
|
09ff6fe0ae | ||
|
|
bd870193dd | ||
|
|
f8858e6756 | ||
|
|
5a095e7a20 | ||
|
|
b12532f27f | ||
|
|
0098a7571c | ||
|
|
2e7ed0e2bb | ||
|
|
04224aa8ca | ||
|
|
2bc602ff89 | ||
|
|
dd9d748439 | ||
|
|
14eede1834 | ||
|
|
c452423b2c | ||
|
|
eac588ad8d | ||
|
|
a97c6cbe9c | ||
|
|
02182fa02a | ||
|
|
a3b3eaea92 | ||
|
|
78cebeceac | ||
|
|
b6b8e2cd6a | ||
|
|
e31bec8546 | ||
|
|
db2b65ebae | ||
|
|
3511ff7054 | ||
|
|
99b0f0474b | ||
|
|
db4d6bf3d6 | ||
|
|
98e1309028 | ||
|
|
5ed2ede620 | ||
|
|
5fca386933 | ||
|
|
803947b9bd | ||
|
|
24553ac46d | ||
|
|
085087a5d3 | ||
|
|
9cfd029643 | ||
|
|
dd9d55bc18 | ||
|
|
8512ad0289 | ||
|
|
cc5581700e | ||
|
|
61cb8a9741 | ||
|
|
11050edb83 | ||
|
|
1d22fafd8b | ||
|
|
f4ed82a8ce | ||
|
|
e0409b43c0 | ||
|
|
702b425af1 | ||
|
|
2630c86ac3 | ||
|
|
45cfcb3be5 | ||
|
|
ce0a8994de | ||
|
|
9c8d030b7f | ||
|
|
681c641aba | ||
|
|
2e85713bb0 | ||
|
|
58b6d7b303 | ||
|
|
e8b52af86e | ||
|
|
ed21f2f24f | ||
|
|
93202d8fbe | ||
|
|
5ce090076d | ||
|
|
4180991cd9 | ||
|
|
0439606c8e | ||
|
|
7dd56c18e9 | ||
|
|
9c12baee96 | ||
|
|
64f7f4e15f | ||
|
|
5ae467fbf9 | ||
|
|
06e4edb239 | ||
|
|
8f1d388b4b | ||
|
|
d500d41ebf | ||
|
|
1e64fb113b | ||
|
|
be7fc19b41 | ||
|
|
1e862dfacb | ||
|
|
d7d33e16d4 | ||
|
|
486d0b8872 |
48
.agents/skills/dependabot-pr-rollup/SKILL.md
Normal file
48
.agents/skills/dependabot-pr-rollup/SKILL.md
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
name: dependabot-pr-rollup
|
||||||
|
description: Find open Dependabot PRs for the current GitHub repo, compare each PR head to its base branch, replay only the net dependency changes in a fresh worktree and branch, run npm validation, and optionally commit, push, and open a PR. Use when you want to batch or manually replicate active Dependabot updates.
|
||||||
|
license: MIT
|
||||||
|
compatibility: Requires git, git worktree, gh CLI auth, npm, and a GitHub repo with an origin remote.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Dependabot PR Rollup
|
||||||
|
|
||||||
|
## When to use
|
||||||
|
|
||||||
|
Use this skill when the user wants to:
|
||||||
|
- find all open Dependabot PRs in the current repo
|
||||||
|
- reproduce their net effect in one local branch
|
||||||
|
- validate the result with the repo's standard npm checks
|
||||||
|
- optionally commit, push, and open a PR
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Inspect the current checkout state, but do not reuse a dirty worktree.
|
||||||
|
2. List open Dependabot PRs with `gh pr list --state open --author app/dependabot`.
|
||||||
|
3. For each PR, collect the title, base branch, head branch, changed files, and relevant diffs.
|
||||||
|
4. Compare each PR head against `origin/<base>` instead of trusting the PR title. Dependabot PRs can already be partially merged, superseded by newer versions, or have no remaining net effect.
|
||||||
|
5. Create a new worktree and branch from `origin/<base>`.
|
||||||
|
6. Reproduce only the remaining dependency changes in the new worktree.
|
||||||
|
- Inspect `package.json` before editing.
|
||||||
|
- Run `npm ci --ignore-scripts` before applying updates.
|
||||||
|
- Use `npm install ... --ignore-scripts` for direct dependency changes so `package-lock.json` stays in sync.
|
||||||
|
7. Run `npm run all`.
|
||||||
|
8. If requested, commit the changed source, lockfile, and generated artifacts, then push and open a PR.
|
||||||
|
|
||||||
|
## Repo-specific notes
|
||||||
|
|
||||||
|
- Use `gh` for GitHub operations.
|
||||||
|
- Keep the user's original checkout untouched by working in a separate worktree.
|
||||||
|
- In this repo, `npm run all` is the safest validation command because it runs build, check, package, and test.
|
||||||
|
- If dependency changes affect bundled output, include the regenerated `dist/` files.
|
||||||
|
|
||||||
|
## Report back
|
||||||
|
|
||||||
|
Always report:
|
||||||
|
- open Dependabot PRs found
|
||||||
|
- which PRs required no net changes
|
||||||
|
- new branch name
|
||||||
|
- new worktree path
|
||||||
|
- files changed
|
||||||
|
- `npm run all` result
|
||||||
|
- if applicable, commit SHA and PR URL
|
||||||
263
.github/copilot-instructions.md
vendored
263
.github/copilot-instructions.md
vendored
@@ -1,263 +0,0 @@
|
|||||||
# Copilot Instructions for setup-uv
|
|
||||||
|
|
||||||
This document provides essential information for GitHub Copilot coding agents working on the `astral-sh/setup-uv` repository.
|
|
||||||
|
|
||||||
## Repository Overview
|
|
||||||
|
|
||||||
**setup-uv** is a GitHub Action that sets up the [uv](https://docs.astral.sh/uv/)
|
|
||||||
Python package installer in GitHub Actions workflows.
|
|
||||||
It's a TypeScript-based action that downloads uv binaries, manages caching, handles version resolution,
|
|
||||||
and configures the environment for subsequent workflow steps.
|
|
||||||
|
|
||||||
### Key Features
|
|
||||||
|
|
||||||
- Downloads and installs specific uv versions from GitHub releases
|
|
||||||
- Supports version resolution from config files (pyproject.toml, uv.toml, .tool-versions)
|
|
||||||
- Implements intelligent caching for both uv cache and Python installations
|
|
||||||
- Provides cross-platform support (Linux, macOS, Windows, including ARM architectures)
|
|
||||||
- Includes problem matchers for Python error reporting
|
|
||||||
- Supports environment activation and custom tool directories
|
|
||||||
|
|
||||||
## Repository Structure
|
|
||||||
|
|
||||||
**Size**: Small-medium repository (~50 source files, ~400 total files including dependencies)
|
|
||||||
**Languages**: TypeScript (primary), JavaScript (compiled output), JSON (configuration)
|
|
||||||
**Runtime**: Node.js 24 (GitHub Actions runtime)
|
|
||||||
**Key Dependencies**: @actions/core, @actions/cache, @actions/tool-cache, @octokit/core
|
|
||||||
|
|
||||||
### Core Architecture
|
|
||||||
|
|
||||||
```
|
|
||||||
src/
|
|
||||||
├── setup-uv.ts # Main entry point and orchestration
|
|
||||||
├── save-cache.ts # Post-action cache saving logic
|
|
||||||
├── update-known-versions.ts # Maintenance script for version updates
|
|
||||||
├── cache/ # Cache management functionality
|
|
||||||
├── download/ # Version resolution and binary downloading
|
|
||||||
├── utils/ # Input parsing, platform detection, configuration
|
|
||||||
└── version/ # Version resolution from various file formats
|
|
||||||
```
|
|
||||||
|
|
||||||
### Key Files and Locations
|
|
||||||
|
|
||||||
- **Action Definition**: `action.yml` - Defines all inputs/outputs and entry points
|
|
||||||
- **Main Source**: `src/setup-uv.ts` - Primary action logic
|
|
||||||
- **Configuration**: `biome.json` (linting), `tsconfig.json` (TypeScript), `jest.config.js` (testing)
|
|
||||||
- **Compiled Output**: `dist/` - Contains compiled Node.js bundles (auto-generated, committed)
|
|
||||||
- **Test Fixtures**: `__tests__/fixtures/` - Sample projects for different configuration scenarios
|
|
||||||
- **Workflows**: `.github/workflows/test.yml` - Comprehensive CI/CD pipeline
|
|
||||||
|
|
||||||
## Build and Development Process
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
- Node.js 24+ (matches GitHub Actions runtime)
|
|
||||||
- npm (included with Node.js)
|
|
||||||
|
|
||||||
### Essential Commands (ALWAYS run in this order)
|
|
||||||
|
|
||||||
#### 1. Install Dependencies
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
**Timing**: ~20-30 seconds
|
|
||||||
**Note**: Always run this first after cloning or when package.json changes
|
|
||||||
|
|
||||||
#### 2. Build TypeScript
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
**Timing**: ~5-10 seconds
|
|
||||||
**Purpose**: Compiles TypeScript source to JavaScript in `lib/` directory
|
|
||||||
|
|
||||||
#### 3. Lint and Format Code
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run check
|
|
||||||
```
|
|
||||||
|
|
||||||
**Timing**: ~2-5 seconds
|
|
||||||
**Tool**: Biome (replaces ESLint/Prettier)
|
|
||||||
**Auto-fixes**: Formatting, import organization, basic linting issues
|
|
||||||
|
|
||||||
#### 4. Package for Distribution
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run package
|
|
||||||
```
|
|
||||||
|
|
||||||
**Timing**: ~20-30 seconds
|
|
||||||
**Purpose**: Creates bundled distributions in `dist/` using @vercel/ncc
|
|
||||||
**Critical**: This step MUST be run before committing - the `dist/` files are used by GitHub Actions
|
|
||||||
|
|
||||||
#### 5. Run Tests
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm test
|
|
||||||
```
|
|
||||||
|
|
||||||
**Timing**: ~10-15 seconds
|
|
||||||
**Framework**: Jest with TypeScript support
|
|
||||||
**Coverage**: Unit tests for version resolution, input parsing, checksum validation
|
|
||||||
|
|
||||||
#### 6. Complete Validation (Recommended)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run all
|
|
||||||
```
|
|
||||||
|
|
||||||
**Timing**: ~60-90 seconds
|
|
||||||
**Purpose**: Runs build → check → package → test in sequence
|
|
||||||
**Use**: Before making pull requests or when unsure about build state
|
|
||||||
|
|
||||||
### Important Build Notes
|
|
||||||
|
|
||||||
**CRITICAL**: Always run `npm run package` after making code changes. The `dist/` directory contains the compiled bundles that GitHub Actions actually executes. Forgetting this step will cause your changes to have no effect.
|
|
||||||
|
|
||||||
**TypeScript Warnings**: You may see ts-jest warnings about "isolatedModules" - these are harmless and don't affect functionality.
|
|
||||||
|
|
||||||
**Biome**: This project uses Biome instead of ESLint/Prettier. Run `npm run check` to fix formatting and linting issues automatically.
|
|
||||||
|
|
||||||
## Testing Strategy
|
|
||||||
|
|
||||||
### Unit Tests
|
|
||||||
|
|
||||||
- **Location**: `__tests__/` directory
|
|
||||||
- **Framework**: Jest with ts-jest transformer
|
|
||||||
- **Coverage**: Version resolution, input parsing, checksum validation, utility functions
|
|
||||||
|
|
||||||
### Integration Tests
|
|
||||||
|
|
||||||
- **Location**: `.github/workflows/test.yml`
|
|
||||||
- **Scope**: Full end-to-end testing across multiple platforms and scenarios
|
|
||||||
- **Key Test Categories**:
|
|
||||||
- Version installation (specific, latest, semver ranges)
|
|
||||||
- Cache behavior (setup, restore, invalidation)
|
|
||||||
- Cross-platform compatibility (Ubuntu, macOS, Windows, ARM)
|
|
||||||
- Configuration file parsing (pyproject.toml, uv.toml, requirements.txt)
|
|
||||||
- Error handling and edge cases
|
|
||||||
|
|
||||||
### Test Fixtures
|
|
||||||
|
|
||||||
Located in `__tests__/fixtures/`, these provide sample projects with different configurations:
|
|
||||||
- `pyproject-toml-project/` - Standard Python project with uv version specification
|
|
||||||
- `uv-toml-project/` - Project using uv.toml configuration
|
|
||||||
- `requirements-txt-project/` - Legacy requirements.txt format
|
|
||||||
- `cache-dir-defined-project/` - Custom cache directory configuration
|
|
||||||
|
|
||||||
## Continuous Integration
|
|
||||||
|
|
||||||
### GitHub Workflows
|
|
||||||
|
|
||||||
#### Primary Test Suite (`.github/workflows/test.yml`)
|
|
||||||
|
|
||||||
- **Triggers**: PRs, pushes to main, manual dispatch
|
|
||||||
- **Matrix**: Multiple OS (Ubuntu, macOS, Windows), architecture (x64, ARM), and configuration combinations
|
|
||||||
- **Duration**: ~5 minutes for full matrix
|
|
||||||
- **Key Validations**:
|
|
||||||
- Cross-platform installation and functionality
|
|
||||||
- Cache behavior and performance
|
|
||||||
- Version resolution from various sources
|
|
||||||
- Tool directory configurations
|
|
||||||
- Problem matcher functionality
|
|
||||||
|
|
||||||
#### Maintenance Workflows
|
|
||||||
|
|
||||||
- **CodeQL Analysis**: Security scanning on pushes/PRs
|
|
||||||
- **Update Known Versions**: Daily job to sync with latest uv releases
|
|
||||||
- **Dependabot**: Automated dependency updates
|
|
||||||
|
|
||||||
### Pre-commit Validation
|
|
||||||
|
|
||||||
The CI runs these checks that you should run locally:
|
|
||||||
1. `npm run all` - Complete build and test suite
|
|
||||||
2. ActionLint - GitHub Actions workflow validation
|
|
||||||
3. Change detection - Ensures no uncommitted build artifacts
|
|
||||||
|
|
||||||
## Key Configuration Files
|
|
||||||
|
|
||||||
### Action Configuration (`action.yml`)
|
|
||||||
|
|
||||||
Defines 20+ inputs including version specifications,
|
|
||||||
cache settings, tool directories, and environment options.
|
|
||||||
This file is the authoritative source for understanding available action parameters.
|
|
||||||
|
|
||||||
### TypeScript Configuration (`tsconfig.json`)
|
|
||||||
|
|
||||||
- Target: ES2024
|
|
||||||
- Module: nodenext (Node.js modules)
|
|
||||||
- Strict mode enabled
|
|
||||||
- Output directory: `lib/`
|
|
||||||
|
|
||||||
### Linting Configuration (`biome.json`)
|
|
||||||
|
|
||||||
- Formatter and linter combined
|
|
||||||
- Enforces consistent code style
|
|
||||||
- Automatically organizes imports and sorts object keys
|
|
||||||
|
|
||||||
## Common Development Patterns
|
|
||||||
|
|
||||||
### Making Code Changes
|
|
||||||
|
|
||||||
1. Edit TypeScript source files in `src/`
|
|
||||||
2. Run `npm run build` to compile
|
|
||||||
3. Run `npm run check` to format and lint
|
|
||||||
4. Run `npm run package` to update distribution bundles
|
|
||||||
5. Run `npm test` to verify functionality
|
|
||||||
6. Commit all changes including `dist/` files
|
|
||||||
|
|
||||||
### Adding New Features
|
|
||||||
|
|
||||||
- Follow existing patterns in `src/utils/inputs.ts` for new action inputs
|
|
||||||
- Update `action.yml` to declare new inputs/outputs
|
|
||||||
- Add corresponding tests in `__tests__/`
|
|
||||||
- Add a test in `.github/workflows/test.yml` if it affects integration
|
|
||||||
- Update README.md with usage examples
|
|
||||||
|
|
||||||
### Cache-Related Changes
|
|
||||||
|
|
||||||
- Cache logic is complex and affects performance significantly
|
|
||||||
- Test with multiple cache scenarios (hit, miss, invalidation)
|
|
||||||
- Consider impact on both GitHub-hosted and self-hosted runners
|
|
||||||
- Validate cache key generation and dependency detection
|
|
||||||
|
|
||||||
### Version Resolution Changes
|
|
||||||
|
|
||||||
- Version resolution supports multiple file formats and precedence rules
|
|
||||||
- Test with fixtures in `__tests__/fixtures/`
|
|
||||||
- Consider backward compatibility with existing projects
|
|
||||||
- Validate semver and PEP 440 specification handling
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### Build Failures
|
|
||||||
|
|
||||||
- **"Module not found"**: Run `npm install` to ensure dependencies are installed
|
|
||||||
- **TypeScript errors**: Check `tsconfig.json` and ensure all imports are valid
|
|
||||||
- **Test failures**: Check if test fixtures have been modified or if logic changes broke assumptions
|
|
||||||
|
|
||||||
### Action Failures in Workflows
|
|
||||||
|
|
||||||
- **Changes not taking effect**: Ensure `npm run package` was run and `dist/` files committed
|
|
||||||
- **Version resolution issues**: Check version specification format and file existence
|
|
||||||
- **Cache problems**: Verify cache key generation and dependency glob patterns
|
|
||||||
|
|
||||||
### Common Gotchas
|
|
||||||
|
|
||||||
- **Forgetting to package**: Code changes won't work without running `npm run package`
|
|
||||||
- **Platform differences**: Windows paths use backslashes, test cross-platform behavior
|
|
||||||
- **Cache invalidation**: Cache keys are sensitive to dependency file changes
|
|
||||||
- **Tool directory permissions**: Some platforms require specific directory setups
|
|
||||||
|
|
||||||
## Trust These Instructions
|
|
||||||
|
|
||||||
These instructions are comprehensive and current. Only search for additional information if:
|
|
||||||
- You encounter specific error messages not covered here
|
|
||||||
- You need to understand implementation details of specific functions
|
|
||||||
- The instructions appear outdated (check repository commit history)
|
|
||||||
|
|
||||||
For most development tasks, following the build process and development patterns outlined above will be sufficient.
|
|
||||||
4
.github/dependabot.yml
vendored
4
.github/dependabot.yml
vendored
@@ -4,8 +4,12 @@ updates:
|
|||||||
directory: /
|
directory: /
|
||||||
schedule:
|
schedule:
|
||||||
interval: daily
|
interval: daily
|
||||||
|
cooldown:
|
||||||
|
default-days: 7
|
||||||
|
|
||||||
- package-ecosystem: npm
|
- package-ecosystem: npm
|
||||||
directory: /
|
directory: /
|
||||||
schedule:
|
schedule:
|
||||||
interval: daily
|
interval: daily
|
||||||
|
cooldown:
|
||||||
|
default-days: 7
|
||||||
|
|||||||
2
.github/release-drafter.yml
vendored
2
.github/release-drafter.yml
vendored
@@ -19,7 +19,7 @@ categories:
|
|||||||
labels:
|
labels:
|
||||||
- "maintenance"
|
- "maintenance"
|
||||||
- "ci"
|
- "ci"
|
||||||
- "update-known-versions"
|
- "update-known-checksums"
|
||||||
- title: "📚 Documentation"
|
- title: "📚 Documentation"
|
||||||
labels:
|
labels:
|
||||||
- "documentation"
|
- "documentation"
|
||||||
|
|||||||
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@@ -41,13 +41,13 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
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@16140ae1a102900babc80a33c44059580f687047 # v4.30.9
|
uses: github/codeql-action/init@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4.32.2
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
source-root: src
|
source-root: src
|
||||||
@@ -59,7 +59,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@16140ae1a102900babc80a33c44059580f687047 # v4.30.9
|
uses: github/codeql-action/autobuild@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4.32.2
|
||||||
|
|
||||||
# ℹ️ 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
|
||||||
@@ -73,4 +73,4 @@ jobs:
|
|||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@16140ae1a102900babc80a33c44059580f687047 # v4.30.9
|
uses: github/codeql-action/analyze@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4.32.2
|
||||||
|
|||||||
2
.github/workflows/release-drafter.yml
vendored
2
.github/workflows/release-drafter.yml
vendored
@@ -19,6 +19,6 @@ jobs:
|
|||||||
pull-requests: read
|
pull-requests: read
|
||||||
steps:
|
steps:
|
||||||
- name: 🚀 Run Release Drafter
|
- name: 🚀 Run Release Drafter
|
||||||
uses: release-drafter/release-drafter@b1476f6e6eb133afa41ed8589daba6dc69b4d3f5 # v6.1.0
|
uses: release-drafter/release-drafter@6db134d15f3909ccc9eefd369f02bd1e9cffdf97 # v6.2.0
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
382
.github/workflows/test.yml
vendored
382
.github/workflows/test.yml
vendored
@@ -21,19 +21,19 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
security-events: write # for zizmor
|
security-events: write # for zizmor
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Actionlint
|
- name: Actionlint
|
||||||
uses: eifinger/actionlint-action@03ff1f78c0670b71017616a37170f327df932030 # v1.9.2
|
uses: eifinger/actionlint-action@7802e0cc3ab3f81cbffb36fb0bf1a3621d994b89 # v1.10.1
|
||||||
- name: Run zizmor
|
- name: Run zizmor
|
||||||
uses: zizmorcore/zizmor-action@e673c3917a1aef3c65c972347ed84ccd013ecda4 # v0.2.0
|
uses: zizmorcore/zizmor-action@0dce2577a4760a2749d8cfb7a84b7d5585ebcb7d # v0.5.0
|
||||||
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||||
with:
|
with:
|
||||||
node-version-file: .nvmrc
|
node-version-file: .nvmrc
|
||||||
cache: npm
|
cache: npm
|
||||||
- run: |
|
- run: |
|
||||||
npm install
|
npm ci --ignore-scripts
|
||||||
- run: |
|
- run: |
|
||||||
npm run all
|
npm run all
|
||||||
- name: Check all jobs are in all-tests-passed.needs
|
- name: Check all jobs are in all-tests-passed.needs
|
||||||
@@ -51,7 +51,7 @@ jobs:
|
|||||||
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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install latest version
|
- name: Install latest version
|
||||||
@@ -76,7 +76,7 @@ jobs:
|
|||||||
test-uv-no-modify-path:
|
test-uv-no-modify-path:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install with UV_NO_MODIFY_PATH set
|
- name: Install with UV_NO_MODIFY_PATH set
|
||||||
@@ -125,7 +125,7 @@ jobs:
|
|||||||
expected-version: "0.1.0"
|
expected-version: "0.1.0"
|
||||||
resolution-strategy: "lowest"
|
resolution-strategy: "lowest"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install version ${{ matrix.input.version-input }} with strategy ${{ matrix.input.resolution-strategy || 'highest' }}
|
- name: Install version ${{ matrix.input.version-input }} with strategy ${{ matrix.input.resolution-strategy || 'highest' }}
|
||||||
@@ -154,7 +154,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
version-input: ["latest", ">=0.8"]
|
version-input: ["latest", ">=0.8"]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install version ${{ matrix.version-input }}
|
- name: Install version ${{ matrix.version-input }}
|
||||||
@@ -182,7 +182,7 @@ jobs:
|
|||||||
- working-directory: "__tests__/fixtures/uv-toml-project"
|
- working-directory: "__tests__/fixtures/uv-toml-project"
|
||||||
expected-version: "0.5.15"
|
expected-version: "0.5.15"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install version from ${{ matrix.input.working-directory }}
|
- name: Install version from ${{ matrix.input.working-directory }}
|
||||||
@@ -208,7 +208,7 @@ jobs:
|
|||||||
- version-file: "__tests__/fixtures/.tool-versions"
|
- version-file: "__tests__/fixtures/.tool-versions"
|
||||||
expected-version: "0.5.15"
|
expected-version: "0.5.15"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install version from ${{ matrix.input.version-file }}
|
- name: Install version from ${{ matrix.input.version-file }}
|
||||||
@@ -225,7 +225,7 @@ jobs:
|
|||||||
test-malformed-pyproject-file-fallback:
|
test-malformed-pyproject-file-fallback:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install using malformed pyproject.toml
|
- name: Install using malformed pyproject.toml
|
||||||
@@ -245,7 +245,7 @@ jobs:
|
|||||||
- os: macos-latest
|
- os: macos-latest
|
||||||
checksum: "a70cbfbf3bb5c08b2f84963b4f12c94e08fbb2468ba418a3bfe1066fbe9e7218"
|
checksum: "a70cbfbf3bb5c08b2f84963b4f12c94e08fbb2468ba418a3bfe1066fbe9e7218"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Checksum matches expected
|
- name: Checksum matches expected
|
||||||
@@ -259,7 +259,7 @@ jobs:
|
|||||||
test-with-explicit-token:
|
test-with-explicit-token:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install default version
|
- name: Install default version
|
||||||
@@ -272,7 +272,7 @@ jobs:
|
|||||||
test-uvx:
|
test-uvx:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install default version
|
- name: Install default version
|
||||||
@@ -285,7 +285,7 @@ jobs:
|
|||||||
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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install default version
|
- name: Install default version
|
||||||
@@ -293,38 +293,17 @@ jobs:
|
|||||||
- run: uv tool install ruff
|
- run: uv tool install ruff
|
||||||
- run: ruff --version
|
- run: ruff --version
|
||||||
|
|
||||||
test-tilde-expansion-tool-dirs:
|
|
||||||
runs-on: selfhosted-ubuntu-arm64
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Setup with cache
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
tool-bin-dir: "~/tool-bin-dir"
|
|
||||||
tool-dir: "~/tool-dir"
|
|
||||||
- name: "Check if tool dirs are expanded"
|
|
||||||
run: |
|
|
||||||
if ! echo "$PATH" | grep -q "/home/ubuntu/tool-bin-dir"; then
|
|
||||||
echo "PATH does not contain /home/ubuntu/tool-bin-dir: $PATH"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ "$UV_TOOL_DIR" != "/home/ubuntu/tool-dir" ]; then
|
|
||||||
echo "UV_TOOL_DIR does not contain /home/ubuntu/tool-dir: $UV_TOOL_DIR"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
test-python-version:
|
test-python-version:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install latest version
|
- name: Install latest version
|
||||||
|
id: setup-uv
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
python-version: 3.13.1t
|
python-version: 3.13.1t
|
||||||
@@ -335,6 +314,14 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
shell: bash
|
shell: bash
|
||||||
|
- name: Verify output python-version is correct
|
||||||
|
run: |
|
||||||
|
if [ "$PYTHON_VERSION" != "3.13.1t" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
PYTHON_VERSION: ${{ steps.setup-uv.outputs.python-version }}
|
||||||
- run: uv sync
|
- run: uv sync
|
||||||
working-directory: __tests__/fixtures/uv-project
|
working-directory: __tests__/fixtures/uv-project
|
||||||
|
|
||||||
@@ -344,7 +331,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install latest version
|
- name: Install latest version
|
||||||
@@ -377,26 +364,144 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
UV_VENV: ${{ steps.setup-uv.outputs.venv }}
|
UV_VENV: ${{ steps.setup-uv.outputs.venv }}
|
||||||
|
|
||||||
test-musl:
|
test-activate-environment-custom-path:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ${{ matrix.os }}
|
||||||
container: alpine
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Install latest version
|
||||||
|
id: setup-uv
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
python-version: 3.13.1t
|
||||||
|
activate-environment: true
|
||||||
|
venv-path: ${{ runner.temp }}/custom-venv
|
||||||
|
- name: Verify VIRTUAL_ENV matches output
|
||||||
|
run: |
|
||||||
|
if [ "$VIRTUAL_ENV" != "$UV_VENV" ]; then
|
||||||
|
echo "VIRTUAL_ENV does not match venv output: $VIRTUAL_ENV vs $UV_VENV"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
UV_VENV: ${{ steps.setup-uv.outputs.venv }}
|
||||||
|
- name: Verify venv location is runner.temp/custom-venv
|
||||||
|
run: |
|
||||||
|
python - <<'PY'
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
venv = Path(os.environ["VIRTUAL_ENV"]).resolve()
|
||||||
|
temp = Path(os.environ["RUNNER_TEMP"]).resolve()
|
||||||
|
|
||||||
|
if venv.name != "custom-venv":
|
||||||
|
raise SystemExit(f"Expected venv name 'custom-venv', got: {venv}")
|
||||||
|
if venv.parent != temp:
|
||||||
|
raise SystemExit(f"Expected venv under {temp}, got: {venv}")
|
||||||
|
if not venv.is_dir():
|
||||||
|
raise SystemExit(f"Venv directory does not exist: {venv}")
|
||||||
|
PY
|
||||||
|
shell: bash
|
||||||
|
- name: Verify packages can be installed
|
||||||
|
run: uv pip install pip
|
||||||
|
shell: bash
|
||||||
|
- name: Verify python runs from custom venv
|
||||||
|
run: |
|
||||||
|
python - <<'PY'
|
||||||
|
import sys
|
||||||
|
if "custom-venv" not in sys.executable:
|
||||||
|
raise SystemExit(f"Python is not running from custom venv: {sys.executable}")
|
||||||
|
PY
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
test-debian-unstable:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: debian:unstable
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install latest version
|
- name: Install latest version
|
||||||
uses: ./
|
uses: ./
|
||||||
|
with:
|
||||||
|
enable-cache: true
|
||||||
- run: uv sync
|
- run: uv sync
|
||||||
working-directory: __tests__/fixtures/uv-project
|
working-directory: __tests__/fixtures/uv-project
|
||||||
|
|
||||||
|
test-musl:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: alpine
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Install latest version
|
||||||
|
id: setup-uv
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
enable-cache: true
|
||||||
|
- name: Verify cache key contains alpine
|
||||||
|
run: |
|
||||||
|
echo "Cache key: $CACHE_KEY"
|
||||||
|
if echo "$CACHE_KEY" | grep -qv "alpine"; then
|
||||||
|
echo "Cache key does not contain 'alpine'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
shell: sh
|
||||||
|
env:
|
||||||
|
CACHE_KEY: ${{ steps.setup-uv.outputs.cache-key }}
|
||||||
|
- run: uv sync
|
||||||
|
working-directory: __tests__/fixtures/uv-project
|
||||||
|
|
||||||
|
test-cache-key-os-version:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: ubuntu-22.04
|
||||||
|
expected-os: "ubuntu-22.04"
|
||||||
|
- os: ubuntu-24.04
|
||||||
|
expected-os: "ubuntu-24.04"
|
||||||
|
- os: macos-14
|
||||||
|
expected-os: "macos-14"
|
||||||
|
- os: macos-15
|
||||||
|
expected-os: "macos-15"
|
||||||
|
- os: windows-2022
|
||||||
|
expected-os: "windows-2022"
|
||||||
|
- os: windows-2025
|
||||||
|
expected-os: "windows-2025"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Setup uv
|
||||||
|
id: setup-uv
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
enable-cache: true
|
||||||
|
- name: Verify cache key contains OS version
|
||||||
|
run: |
|
||||||
|
echo "Cache key: $CACHE_KEY"
|
||||||
|
if [[ "$CACHE_KEY" != *"${{ matrix.expected-os }}"* ]]; then
|
||||||
|
echo "Cache key does not contain expected OS version: ${{ matrix.expected-os }}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
CACHE_KEY: ${{ steps.setup-uv.outputs.cache-key }}
|
||||||
|
|
||||||
test-setup-cache:
|
test-setup-cache:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
enable-cache: ["true", "false", "auto"]
|
enable-cache: ["true", "false", "auto"]
|
||||||
os: ["ubuntu-latest", "selfhosted-ubuntu-arm64", "windows-latest"]
|
os: ["ubuntu-latest", "windows-latest"]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup with cache
|
- name: Setup with cache
|
||||||
@@ -412,10 +517,10 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
enable-cache: ["true", "false", "auto"]
|
enable-cache: ["true", "false", "auto"]
|
||||||
os: ["ubuntu-latest", "selfhosted-ubuntu-arm64", "windows-latest"]
|
os: ["ubuntu-latest", "windows-latest"]
|
||||||
needs: test-setup-cache
|
needs: test-setup-cache
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Restore with cache
|
- name: Restore with cache
|
||||||
@@ -434,7 +539,7 @@ jobs:
|
|||||||
CACHE_HIT: ${{ steps.restore.outputs.cache-hit }}
|
CACHE_HIT: ${{ steps.restore.outputs.cache-hit }}
|
||||||
shell: bash
|
shell: bash
|
||||||
- name: Cache was not hit
|
- name: Cache was not hit
|
||||||
if: ${{ matrix.enable-cache == 'false' || (matrix.enable-cache == 'auto' && matrix.os == 'selfhosted-ubuntu-arm64') }}
|
if: ${{ matrix.enable-cache == 'false' }}
|
||||||
run: |
|
run: |
|
||||||
if [ "$CACHE_HIT" == "true" ]; then
|
if [ "$CACHE_HIT" == "true" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
@@ -449,7 +554,7 @@ jobs:
|
|||||||
test-setup-cache-requirements-txt:
|
test-setup-cache-requirements-txt:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup with cache
|
- name: Setup with cache
|
||||||
@@ -465,7 +570,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: test-setup-cache-requirements-txt
|
needs: test-setup-cache-requirements-txt
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Restore with cache
|
- name: Restore with cache
|
||||||
@@ -489,7 +594,7 @@ jobs:
|
|||||||
test-setup-cache-dependency-glob:
|
test-setup-cache-dependency-glob:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup with cache
|
- name: Setup with cache
|
||||||
@@ -506,7 +611,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: test-setup-cache-dependency-glob
|
needs: test-setup-cache-dependency-glob
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Change pyproject.toml
|
- name: Change pyproject.toml
|
||||||
@@ -534,7 +639,7 @@ jobs:
|
|||||||
test-setup-cache-save-cache-false:
|
test-setup-cache-save-cache-false:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup with cache
|
- name: Setup with cache
|
||||||
@@ -550,7 +655,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: test-setup-cache-save-cache-false
|
needs: test-setup-cache-save-cache-false
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Restore with cache
|
- name: Restore with cache
|
||||||
@@ -570,7 +675,7 @@ jobs:
|
|||||||
test-setup-cache-restore-cache-false:
|
test-setup-cache-restore-cache-false:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup with cache
|
- name: Setup with cache
|
||||||
@@ -585,7 +690,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: test-setup-cache-restore-cache-false
|
needs: test-setup-cache-restore-cache-false
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Restore with cache
|
- name: Restore with cache
|
||||||
@@ -611,11 +716,9 @@ jobs:
|
|||||||
expected-cache-dir: "/home/runner/work/_temp/setup-uv-cache"
|
expected-cache-dir: "/home/runner/work/_temp/setup-uv-cache"
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
expected-cache-dir: "D:\\a\\_temp\\setup-uv-cache"
|
expected-cache-dir: "D:\\a\\_temp\\setup-uv-cache"
|
||||||
- os: selfhosted-ubuntu-arm64
|
|
||||||
expected-cache-dir: "/home/ubuntu/.cache/uv"
|
|
||||||
runs-on: ${{ matrix.inputs.os }}
|
runs-on: ${{ matrix.inputs.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup with cache
|
- name: Setup with cache
|
||||||
@@ -633,7 +736,7 @@ jobs:
|
|||||||
test-cache-local-cache-disabled:
|
test-cache-local-cache-disabled:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup without cache
|
- name: Setup without cache
|
||||||
@@ -649,99 +752,30 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
test-setup-cache-local:
|
test-cache-local-cache-disabled-but-explicit-path:
|
||||||
runs-on: selfhosted-ubuntu-arm64
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup with cache
|
- name: Setup without cache
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
enable-cache: true
|
enable-cache: false
|
||||||
cache-suffix: ${{ github.run_id }}-${{ github.run_attempt }}-test-setup-cache-local
|
cache-local-path: /tmp/uv-cache-disabled
|
||||||
cache-local-path: /tmp/uv-cache
|
|
||||||
- run: uv sync
|
- name: Check UV_CACHE_DIR is set
|
||||||
working-directory: __tests__/fixtures/uv-project
|
|
||||||
test-restore-cache-local:
|
|
||||||
runs-on: selfhosted-ubuntu-arm64
|
|
||||||
needs: test-setup-cache-local
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Restore with cache
|
|
||||||
id: restore
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
enable-cache: true
|
|
||||||
cache-suffix: ${{ github.run_id }}-${{ github.run_attempt }}-test-setup-cache-local
|
|
||||||
cache-local-path: /tmp/uv-cache
|
|
||||||
- name: Cache was hit
|
|
||||||
run: |
|
run: |
|
||||||
if [ "$CACHE_HIT" != "true" ]; then
|
if [ "$UV_CACHE_DIR" != "/tmp/uv-cache-disabled" ]; then
|
||||||
|
echo "UV_CACHE_DIR should be set when cache is disabled but explicit path is provided"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
env:
|
|
||||||
CACHE_HIT: ${{ steps.restore.outputs.cache-hit }}
|
|
||||||
- run: uv sync
|
|
||||||
working-directory: __tests__/fixtures/uv-project
|
|
||||||
|
|
||||||
test-tilde-expansion-cache-local-path:
|
|
||||||
runs-on: selfhosted-ubuntu-arm64
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Create cache directory
|
|
||||||
run: mkdir -p ~/uv-cache
|
|
||||||
shell: bash
|
|
||||||
- name: Setup with cache
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
cache-local-path: ~/uv-cache/cache-local-path
|
|
||||||
- run: uv sync
|
|
||||||
working-directory: __tests__/fixtures/uv-project
|
|
||||||
|
|
||||||
test-tilde-expansion-cache-dependency-glob:
|
|
||||||
runs-on: selfhosted-ubuntu-arm64
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Create cache directory
|
|
||||||
run: mkdir -p ~/uv-cache
|
|
||||||
shell: bash
|
|
||||||
- name: Create cache dependency glob file
|
|
||||||
run: touch ~/uv-cache.glob
|
|
||||||
shell: bash
|
|
||||||
- name: Setup with cache
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
enable-cache: true
|
|
||||||
cache-local-path: ~/uv-cache/cache-dependency-glob
|
|
||||||
cache-dependency-glob: "~/uv-cache.glob"
|
|
||||||
- run: uv sync
|
|
||||||
working-directory: __tests__/fixtures/uv-project
|
|
||||||
|
|
||||||
cleanup-tilde-expansion-tests:
|
|
||||||
needs:
|
|
||||||
- test-tilde-expansion-cache-local-path
|
|
||||||
- test-tilde-expansion-cache-dependency-glob
|
|
||||||
if: always()
|
|
||||||
runs-on: selfhosted-ubuntu-arm64
|
|
||||||
steps:
|
|
||||||
- name: Remove cache directory
|
|
||||||
run: rm -rf ~/uv-cache
|
|
||||||
shell: bash
|
|
||||||
- name: Remove cache dependency glob file
|
|
||||||
run: rm -f ~/uv-cache.glob
|
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
test-no-python-version:
|
test-no-python-version:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Fake pyproject.toml at root
|
- name: Fake pyproject.toml at root
|
||||||
@@ -756,7 +790,7 @@ jobs:
|
|||||||
test-custom-manifest-file:
|
test-custom-manifest-file:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install from custom manifest file
|
- name: Install from custom manifest file
|
||||||
@@ -775,7 +809,7 @@ jobs:
|
|||||||
test-absolute-path:
|
test-absolute-path:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Create requirements.txt
|
- name: Create requirements.txt
|
||||||
@@ -795,7 +829,7 @@ jobs:
|
|||||||
test-relative-path:
|
test-relative-path:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: mkdir
|
- name: mkdir
|
||||||
@@ -819,7 +853,7 @@ jobs:
|
|||||||
test-cache-prune-force:
|
test-cache-prune-force:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup uv
|
- name: Setup uv
|
||||||
@@ -836,7 +870,7 @@ jobs:
|
|||||||
test-cache-dir-from-file:
|
test-cache-dir-from-file:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Verify uv cache dir is not populated
|
- name: Verify uv cache dir is not populated
|
||||||
@@ -858,10 +892,33 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
test-cache-python-missing-managed-install-dir:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
UV_PYTHON_INSTALL_DIR: /tmp/missing-uv-python
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Setup uv with cache and python cache enabled
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
enable-cache: true
|
||||||
|
cache-python: true
|
||||||
|
python-version: "3.12"
|
||||||
|
cache-local-path: /tmp/setup-uv-cache
|
||||||
|
cache-suffix: ${{ github.run_id }}-${{ github.run_attempt }}-test-cache-python-missing-managed-install-dir
|
||||||
|
- name: Ensure uv cache dir exists so only python-cache behavior is tested
|
||||||
|
run: uv sync
|
||||||
|
working-directory: __tests__/fixtures/uv-project
|
||||||
|
shell: bash
|
||||||
|
- name: Ensure managed Python install dir does not exist and this does not break caching
|
||||||
|
run: rm -rf "$UV_PYTHON_INSTALL_DIR"
|
||||||
|
|
||||||
test-cache-python-installs:
|
test-cache-python-installs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Verify Python install dir is not populated
|
- name: Verify Python install dir is not populated
|
||||||
@@ -888,7 +945,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: test-cache-python-installs
|
needs: test-cache-python-installs
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Verify Python install dir does not exist
|
- name: Verify Python install dir does not exist
|
||||||
@@ -916,7 +973,7 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
env:
|
env:
|
||||||
CACHE_HIT: ${{ steps.restore.outputs.cache-hit }}
|
CACHE_HIT: ${{ steps.restore.outputs.python-cache-hit }}
|
||||||
- run: uv sync --managed-python
|
- run: uv sync --managed-python
|
||||||
working-directory: __tests__/fixtures/uv-project
|
working-directory: __tests__/fixtures/uv-project
|
||||||
|
|
||||||
@@ -928,11 +985,9 @@ jobs:
|
|||||||
expected-python-dir: "/home/runner/work/_temp/uv-python-dir"
|
expected-python-dir: "/home/runner/work/_temp/uv-python-dir"
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
expected-python-dir: "D:\\a\\_temp\\uv-python-dir"
|
expected-python-dir: "D:\\a\\_temp\\uv-python-dir"
|
||||||
- os: selfhosted-ubuntu-arm64
|
|
||||||
expected-python-dir: "/home/ubuntu/.local/share/uv/python"
|
|
||||||
runs-on: ${{ matrix.inputs.os }}
|
runs-on: ${{ matrix.inputs.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install latest version
|
- name: Install latest version
|
||||||
@@ -951,7 +1006,7 @@ jobs:
|
|||||||
test-act:
|
test-act:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install act
|
- name: Install act
|
||||||
@@ -963,6 +1018,15 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
|
||||||
|
validate-typings:
|
||||||
|
runs-on: "ubuntu-latest"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Validate typings
|
||||||
|
uses: typesafegithub/github-actions-typing@9ddf35b71a482be7d8922b28e8d00df16b77e315 # v2.2.2
|
||||||
|
|
||||||
all-tests-passed:
|
all-tests-passed:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs:
|
needs:
|
||||||
@@ -978,12 +1042,15 @@ jobs:
|
|||||||
- test-with-explicit-token
|
- test-with-explicit-token
|
||||||
- test-uvx
|
- test-uvx
|
||||||
- test-tool-install
|
- test-tool-install
|
||||||
- test-tilde-expansion-tool-dirs
|
|
||||||
- test-python-version
|
- test-python-version
|
||||||
- test-activate-environment
|
- test-activate-environment
|
||||||
|
- test-activate-environment-custom-path
|
||||||
|
- test-debian-unstable
|
||||||
- test-musl
|
- test-musl
|
||||||
|
- test-cache-key-os-version
|
||||||
- test-cache-local
|
- test-cache-local
|
||||||
- test-cache-local-cache-disabled
|
- test-cache-local-cache-disabled
|
||||||
|
- test-cache-local-cache-disabled-but-explicit-path
|
||||||
- test-setup-cache
|
- test-setup-cache
|
||||||
- test-restore-cache
|
- test-restore-cache
|
||||||
- test-setup-cache-requirements-txt
|
- test-setup-cache-requirements-txt
|
||||||
@@ -994,21 +1061,18 @@ jobs:
|
|||||||
- test-restore-cache-save-cache-false
|
- test-restore-cache-save-cache-false
|
||||||
- test-setup-cache-restore-cache-false
|
- test-setup-cache-restore-cache-false
|
||||||
- test-restore-cache-restore-cache-false
|
- test-restore-cache-restore-cache-false
|
||||||
- test-setup-cache-local
|
|
||||||
- test-restore-cache-local
|
|
||||||
- test-tilde-expansion-cache-local-path
|
|
||||||
- test-tilde-expansion-cache-dependency-glob
|
|
||||||
- cleanup-tilde-expansion-tests
|
|
||||||
- test-no-python-version
|
- test-no-python-version
|
||||||
- test-custom-manifest-file
|
- test-custom-manifest-file
|
||||||
- test-absolute-path
|
- test-absolute-path
|
||||||
- test-relative-path
|
- test-relative-path
|
||||||
- test-cache-prune-force
|
- test-cache-prune-force
|
||||||
- test-cache-dir-from-file
|
- test-cache-dir-from-file
|
||||||
|
- test-cache-python-missing-managed-install-dir
|
||||||
- test-cache-python-installs
|
- test-cache-python-installs
|
||||||
- test-restore-python-installs
|
- test-restore-python-installs
|
||||||
- test-python-install-dir
|
- test-python-install-dir
|
||||||
- test-act
|
- test-act
|
||||||
|
- validate-typings
|
||||||
if: always()
|
if: always()
|
||||||
steps:
|
steps:
|
||||||
- name: All tests passed
|
- name: All tests passed
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
name: "Update known versions"
|
name: "Update known checksums"
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
@@ -15,19 +15,17 @@ jobs:
|
|||||||
contents: write
|
contents: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: true
|
persist-credentials: true
|
||||||
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "20"
|
||||||
- name: Update known versions
|
- name: Update known checksums
|
||||||
id: update-known-versions
|
id: update-known-checksums
|
||||||
run:
|
run:
|
||||||
node dist/update-known-versions/index.js
|
node dist/update-known-checksums/index.js
|
||||||
src/download/checksum/known-checksums.ts
|
src/download/checksum/known-checksums.ts
|
||||||
version-manifest.json
|
|
||||||
${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Check for changes
|
- name: Check for changes
|
||||||
id: changes-exist
|
id: changes-exist
|
||||||
run: |
|
run: |
|
||||||
@@ -39,7 +37,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
- name: Compile changes
|
- name: Compile changes
|
||||||
if: ${{ steps.changes-exist.outputs.changes-exist == 'true' }}
|
if: ${{ steps.changes-exist.outputs.changes-exist == 'true' }}
|
||||||
run: npm ci && npm run all
|
run: npm ci --ignore-scripts && npm run all
|
||||||
- name: Commit and push changes
|
- name: Commit and push changes
|
||||||
if: ${{ steps.changes-exist.outputs.changes-exist == 'true' }}
|
if: ${{ steps.changes-exist.outputs.changes-exist == 'true' }}
|
||||||
id: commit-and-push
|
id: commit-and-push
|
||||||
@@ -48,23 +46,23 @@ jobs:
|
|||||||
git config user.name "$GITHUB_ACTOR"
|
git config user.name "$GITHUB_ACTOR"
|
||||||
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
||||||
git add .
|
git add .
|
||||||
git commit -m "chore: update known versions for $LATEST_VERSION"
|
git commit -m "chore: update known checksums for $LATEST_VERSION"
|
||||||
git push origin HEAD:refs/heads/main
|
git push origin HEAD:refs/heads/main
|
||||||
env:
|
env:
|
||||||
LATEST_VERSION: ${{ steps.update-known-versions.outputs.latest-version }}
|
LATEST_VERSION: ${{ steps.update-known-checksums.outputs.latest-version }}
|
||||||
|
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
if: ${{ steps.changes-exist.outputs.changes-exist == 'true' && steps.commit-and-push.outcome != 'success' }}
|
if: ${{ steps.changes-exist.outputs.changes-exist == 'true' && steps.commit-and-push.outcome != 'success' }}
|
||||||
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
|
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
|
||||||
with:
|
with:
|
||||||
commit-message: "chore: update known checksums"
|
commit-message: "chore: update known checksums"
|
||||||
title:
|
title:
|
||||||
"chore: update known checksums for ${{
|
"chore: update known checksums for ${{
|
||||||
steps.update-known-versions.outputs.latest-version }}"
|
steps.update-known-checksums.outputs.latest-version }}"
|
||||||
body:
|
body:
|
||||||
"chore: update known checksums for ${{
|
"chore: update known checksums for ${{
|
||||||
steps.update-known-versions.outputs.latest-version }}"
|
steps.update-known-checksums.outputs.latest-version }}"
|
||||||
base: main
|
base: main
|
||||||
labels: "automated-pr,update-known-versions"
|
labels: "automated-pr,update-known-checksums"
|
||||||
branch: update-known-versions-pr
|
branch: update-known-checksums-pr
|
||||||
delete-branch: true
|
delete-branch: true
|
||||||
@@ -17,7 +17,7 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: true # needed for git push below
|
persist-credentials: true # needed for git push below
|
||||||
- name: Update Major Minor Tags
|
- name: Update Major Minor Tags
|
||||||
|
|||||||
13
AGENTS.md
Normal file
13
AGENTS.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# setup-uv agent notes
|
||||||
|
|
||||||
|
This repository is a TypeScript-based GitHub Action for installing `uv` in GitHub Actions workflows. It also supports restoring/saving the `uv` cache and optional managed-Python caching.
|
||||||
|
|
||||||
|
- The published action runs the committed bundles in `dist/`, not the TypeScript in `src/`. After any code change, run `npm run package` and commit the resulting `dist/` updates.
|
||||||
|
- Standard local validation is:
|
||||||
|
1. `npm ci --ignore-scripts`
|
||||||
|
2. `npm run all`
|
||||||
|
- `npm run check` uses Biome (not ESLint/Prettier) and rewrites files in place.
|
||||||
|
- User-facing changes are usually multi-file changes. If you add or change inputs, outputs, or behavior, update `action.yml`, the implementation in `src/`, tests in `__tests__/`, relevant docs/README, and then re-package.
|
||||||
|
- The easiest areas to regress are version resolution and caching. When touching them, add or update tests for precedence, cache invalidation, and cross-platform path behavior.
|
||||||
|
- Workflow edits have extra CI-only checks (`actionlint` and `zizmor`); `npm run all` does not cover them.
|
||||||
|
- Before finishing, make sure validation does not leave generated or formatting-only diffs behind.
|
||||||
28
README.md
28
README.md
@@ -59,13 +59,16 @@ Have a look under [Advanced Configuration](#advanced-configuration) for detailed
|
|||||||
# Use uv venv to activate a venv ready to be used by later steps
|
# Use uv venv to activate a venv ready to be used by later steps
|
||||||
activate-environment: "false"
|
activate-environment: "false"
|
||||||
|
|
||||||
|
# Custom path for the virtual environment when using activate-environment (default: .venv in the working directory)
|
||||||
|
venv-path: ""
|
||||||
|
|
||||||
# The directory to execute all commands in and look for files such as pyproject.toml
|
# The directory to execute all commands in and look for files such as pyproject.toml
|
||||||
working-directory: ""
|
working-directory: ""
|
||||||
|
|
||||||
# The checksum of the uv version to install
|
# The checksum of the uv version to install
|
||||||
checksum: ""
|
checksum: ""
|
||||||
|
|
||||||
# Used to increase the rate limit when retrieving versions and downloading uv
|
# Used when downloading uv from GitHub releases
|
||||||
github-token: ${{ github.token }}
|
github-token: ${{ github.token }}
|
||||||
|
|
||||||
# Enable uploading of the uv cache: true, false, or auto (enabled on GitHub-hosted runners, disabled on self-hosted runners)
|
# Enable uploading of the uv cache: true, false, or auto (enabled on GitHub-hosted runners, disabled on self-hosted runners)
|
||||||
@@ -111,7 +114,7 @@ Have a look under [Advanced Configuration](#advanced-configuration) for detailed
|
|||||||
# Custom path to set UV_TOOL_BIN_DIR to
|
# Custom path to set UV_TOOL_BIN_DIR to
|
||||||
tool-bin-dir: ""
|
tool-bin-dir: ""
|
||||||
|
|
||||||
# URL to the manifest file containing available versions and download URLs
|
# URL to a custom manifest file (NDJSON preferred, legacy JSON array is deprecated)
|
||||||
manifest-file: ""
|
manifest-file: ""
|
||||||
|
|
||||||
# Add problem matchers
|
# Add problem matchers
|
||||||
@@ -125,6 +128,8 @@ Have a look under [Advanced Configuration](#advanced-configuration) for detailed
|
|||||||
- `uvx-path`: The path to the installed uvx binary.
|
- `uvx-path`: The path to the installed uvx binary.
|
||||||
- `cache-hit`: A boolean value to indicate a cache entry was found.
|
- `cache-hit`: A boolean value to indicate a cache entry was found.
|
||||||
- `venv`: Path to the activated venv if activate-environment is true.
|
- `venv`: Path to the activated venv if activate-environment is true.
|
||||||
|
- `python-version`: The Python version that was set.
|
||||||
|
- `python-cache-hit`: A boolean value to indicate the Python cache entry was found.
|
||||||
|
|
||||||
### Python version
|
### Python version
|
||||||
|
|
||||||
@@ -165,7 +170,7 @@ You can set the working directory with the `working-directory` input.
|
|||||||
This controls where we look for `pyproject.toml`, `uv.toml` and `.python-version` files
|
This controls where we look for `pyproject.toml`, `uv.toml` and `.python-version` files
|
||||||
which are used to determine the version of uv and python to install.
|
which are used to determine the version of uv and python to install.
|
||||||
|
|
||||||
It also controls where [the venv gets created](#activate-environment).
|
It also controls where [the venv gets created](#activate-environment), unless `venv-path` is set.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Install uv based on the config files in the working-directory
|
- name: Install uv based on the config files in the working-directory
|
||||||
@@ -185,10 +190,12 @@ For more advanced configuration options, see our detailed documentation:
|
|||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
This action downloads uv from the uv repo's official
|
By default, this action resolves uv versions from
|
||||||
[GitHub Releases](https://github.com/astral-sh/uv) and uses the
|
[`astral-sh/versions`](https://github.com/astral-sh/versions) (NDJSON) and downloads uv from the
|
||||||
[GitHub Actions Toolkit](https://github.com/actions/toolkit) to cache it as a tool to speed up
|
official [GitHub Releases](https://github.com/astral-sh/uv).
|
||||||
consecutive runs on self-hosted runners.
|
|
||||||
|
It then uses the [GitHub Actions Toolkit](https://github.com/actions/toolkit) to cache uv as a
|
||||||
|
tool to speed up consecutive runs on self-hosted runners.
|
||||||
|
|
||||||
The installed version of uv is then added to the runner PATH, enabling later steps to invoke it
|
The installed version of uv is then added to the runner PATH, enabling later steps to invoke it
|
||||||
by name (`uv`).
|
by name (`uv`).
|
||||||
@@ -200,7 +207,8 @@ by name (`uv`).
|
|||||||
With `setup-uv`, you can install a specific version of Python using `uv python install` rather than
|
With `setup-uv`, you can install a specific version of Python using `uv python install` rather than
|
||||||
relying on `actions/setup-python`.
|
relying on `actions/setup-python`.
|
||||||
|
|
||||||
Using `actions/setup-python` can be faster, because GitHub caches the Python versions alongside the runner.
|
Using `actions/setup-python` can be faster (~1s), because GitHub includes several Python versions in the runner image
|
||||||
|
which are available to get activated by `actions/setup-python` without having to download them.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
@@ -273,7 +281,7 @@ the cache will not be found and the warning `No GitHub Actions cache found for k
|
|||||||
While this might be irritating at first, it is expected behaviour and the cache will be created
|
While this might be irritating at first, it is expected behaviour and the cache will be created
|
||||||
and reused in later workflows.
|
and reused in later workflows.
|
||||||
|
|
||||||
The reason for the warning is, that we have to way to know if this is the first run of a new
|
The reason for the warning is that we have to way to know if this is the first run of a new
|
||||||
cache key or the user accidentally misconfigured the cache-dependency-glob
|
cache key or the user accidentally misconfigured the cache-dependency-glob
|
||||||
or cache-suffix (see [Caching documentation](docs/caching.md)) and the cache never gets used.
|
or cache-suffix (see [Caching documentation](docs/caching.md)) and the cache never gets used.
|
||||||
|
|
||||||
@@ -286,7 +294,7 @@ Running `actions/checkout` after `setup-uv` **is not supported**.
|
|||||||
|
|
||||||
### Does `setup-uv` also install my project or its dependencies automatically?
|
### Does `setup-uv` also install my project or its dependencies automatically?
|
||||||
|
|
||||||
No, `setup-uv` alone wont install any libraries from your `pyproject.toml` or `requirements.txt`, it only sets up `uv`.
|
No, `setup-uv` alone won't install any libraries from your `pyproject.toml` or `requirements.txt`, it only sets up `uv`.
|
||||||
You should run `uv sync` or `uv pip install .` separately, or use `uv run ...` to ensure necessary dependencies are installed.
|
You should run `uv sync` or `uv pip install .` separately, or use `uv run ...` to ensure necessary dependencies are installed.
|
||||||
|
|
||||||
### Why is a changed cache not detected and not the full cache uploaded?
|
### Why is a changed cache not detected and not the full cache uploaded?
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import {
|
|||||||
validateChecksum,
|
validateChecksum,
|
||||||
} from "../../../src/download/checksum/checksum";
|
} from "../../../src/download/checksum/checksum";
|
||||||
|
|
||||||
|
const validChecksum =
|
||||||
|
"f3da96ec7e995debee7f5d52ecd034dfb7074309a1da42f76429ecb814d813a3";
|
||||||
|
const filePath = "__tests__/fixtures/checksumfile";
|
||||||
|
|
||||||
test("checksum should match", async () => {
|
test("checksum should match", async () => {
|
||||||
const validChecksum =
|
|
||||||
"f3da96ec7e995debee7f5d52ecd034dfb7074309a1da42f76429ecb814d813a3";
|
|
||||||
const filePath = "__tests__/fixtures/checksumfile";
|
|
||||||
// string params don't matter only test the checksum mechanism, not known checksums
|
// string params don't matter only test the checksum mechanism, not known checksums
|
||||||
await validateChecksum(
|
await validateChecksum(
|
||||||
validChecksum,
|
validChecksum,
|
||||||
@@ -18,6 +19,16 @@ test("checksum should match", async () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("provided checksum beats known checksums", async () => {
|
||||||
|
await validateChecksum(
|
||||||
|
validChecksum,
|
||||||
|
filePath,
|
||||||
|
"x86_64",
|
||||||
|
"unknown-linux-gnu",
|
||||||
|
"0.3.0",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
type KnownVersionFixture = { version: string; known: boolean };
|
type KnownVersionFixture = { version: string; known: boolean };
|
||||||
|
|
||||||
it.each<KnownVersionFixture>([
|
it.each<KnownVersionFixture>([
|
||||||
@@ -29,9 +40,9 @@ it.each<KnownVersionFixture>([
|
|||||||
known: false,
|
known: false,
|
||||||
version: "0.0.15",
|
version: "0.0.15",
|
||||||
},
|
},
|
||||||
])(
|
])("isknownVersion should return $known for version $version", ({
|
||||||
"isknownVersion should return $known for version $version",
|
version,
|
||||||
({ version, known }) => {
|
known,
|
||||||
expect(isknownVersion(version)).toBe(known);
|
}) => {
|
||||||
},
|
expect(isknownVersion(version)).toBe(known);
|
||||||
);
|
});
|
||||||
|
|||||||
256
__tests__/download/download-version.test.ts
Normal file
256
__tests__/download/download-version.test.ts
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
import { beforeEach, describe, expect, it, jest } from "@jest/globals";
|
||||||
|
|
||||||
|
const mockInfo = jest.fn();
|
||||||
|
const mockWarning = jest.fn();
|
||||||
|
|
||||||
|
jest.mock("@actions/core", () => ({
|
||||||
|
debug: jest.fn(),
|
||||||
|
info: mockInfo,
|
||||||
|
warning: mockWarning,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: Mock requires flexible typing in tests.
|
||||||
|
const mockDownloadTool = jest.fn<any>();
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: Mock requires flexible typing in tests.
|
||||||
|
const mockExtractTar = jest.fn<any>();
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: Mock requires flexible typing in tests.
|
||||||
|
const mockExtractZip = jest.fn<any>();
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: Mock requires flexible typing in tests.
|
||||||
|
const mockCacheDir = jest.fn<any>();
|
||||||
|
|
||||||
|
jest.mock("@actions/tool-cache", () => {
|
||||||
|
const actual = jest.requireActual("@actions/tool-cache") as Record<
|
||||||
|
string,
|
||||||
|
unknown
|
||||||
|
>;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...actual,
|
||||||
|
cacheDir: mockCacheDir,
|
||||||
|
downloadTool: mockDownloadTool,
|
||||||
|
extractTar: mockExtractTar,
|
||||||
|
extractZip: mockExtractZip,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: Mock requires flexible typing in tests.
|
||||||
|
const mockGetLatestVersionFromNdjson = jest.fn<any>();
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: Mock requires flexible typing in tests.
|
||||||
|
const mockGetAllVersionsFromNdjson = jest.fn<any>();
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: Mock requires flexible typing in tests.
|
||||||
|
const mockGetArtifactFromNdjson = jest.fn<any>();
|
||||||
|
|
||||||
|
jest.mock("../../src/download/versions-client", () => ({
|
||||||
|
getAllVersions: mockGetAllVersionsFromNdjson,
|
||||||
|
getArtifact: mockGetArtifactFromNdjson,
|
||||||
|
getLatestVersion: mockGetLatestVersionFromNdjson,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: Mock requires flexible typing in tests.
|
||||||
|
const mockGetAllManifestVersions = jest.fn<any>();
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: Mock requires flexible typing in tests.
|
||||||
|
const mockGetLatestVersionInManifest = jest.fn<any>();
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: Mock requires flexible typing in tests.
|
||||||
|
const mockGetManifestArtifact = jest.fn<any>();
|
||||||
|
|
||||||
|
jest.mock("../../src/download/version-manifest", () => ({
|
||||||
|
getAllVersions: mockGetAllManifestVersions,
|
||||||
|
getLatestKnownVersion: mockGetLatestVersionInManifest,
|
||||||
|
getManifestArtifact: mockGetManifestArtifact,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: Mock requires flexible typing in tests.
|
||||||
|
const mockValidateChecksum = jest.fn<any>();
|
||||||
|
|
||||||
|
jest.mock("../../src/download/checksum/checksum", () => ({
|
||||||
|
validateChecksum: mockValidateChecksum,
|
||||||
|
}));
|
||||||
|
|
||||||
|
import {
|
||||||
|
downloadVersionFromManifest,
|
||||||
|
downloadVersionFromNdjson,
|
||||||
|
resolveVersion,
|
||||||
|
} from "../../src/download/download-version";
|
||||||
|
|
||||||
|
describe("download-version", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockInfo.mockReset();
|
||||||
|
mockWarning.mockReset();
|
||||||
|
mockDownloadTool.mockReset();
|
||||||
|
mockExtractTar.mockReset();
|
||||||
|
mockExtractZip.mockReset();
|
||||||
|
mockCacheDir.mockReset();
|
||||||
|
mockGetLatestVersionFromNdjson.mockReset();
|
||||||
|
mockGetAllVersionsFromNdjson.mockReset();
|
||||||
|
mockGetArtifactFromNdjson.mockReset();
|
||||||
|
mockGetAllManifestVersions.mockReset();
|
||||||
|
mockGetLatestVersionInManifest.mockReset();
|
||||||
|
mockGetManifestArtifact.mockReset();
|
||||||
|
mockValidateChecksum.mockReset();
|
||||||
|
|
||||||
|
mockDownloadTool.mockResolvedValue("/tmp/downloaded");
|
||||||
|
mockExtractTar.mockResolvedValue("/tmp/extracted");
|
||||||
|
mockExtractZip.mockResolvedValue("/tmp/extracted");
|
||||||
|
mockCacheDir.mockResolvedValue("/tmp/cached");
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("resolveVersion", () => {
|
||||||
|
it("uses astral-sh/versions to resolve latest", async () => {
|
||||||
|
mockGetLatestVersionFromNdjson.mockResolvedValue("0.9.26");
|
||||||
|
|
||||||
|
const version = await resolveVersion("latest", undefined);
|
||||||
|
|
||||||
|
expect(version).toBe("0.9.26");
|
||||||
|
expect(mockGetLatestVersionFromNdjson).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses astral-sh/versions to resolve available versions", async () => {
|
||||||
|
mockGetAllVersionsFromNdjson.mockResolvedValue(["0.9.26", "0.9.25"]);
|
||||||
|
|
||||||
|
const version = await resolveVersion("^0.9.0", undefined);
|
||||||
|
|
||||||
|
expect(version).toBe("0.9.26");
|
||||||
|
expect(mockGetAllVersionsFromNdjson).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not fall back when astral-sh/versions fails", async () => {
|
||||||
|
mockGetLatestVersionFromNdjson.mockRejectedValue(
|
||||||
|
new Error("NDJSON unavailable"),
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(resolveVersion("latest", undefined)).rejects.toThrow(
|
||||||
|
"NDJSON unavailable",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses manifest-file when provided", async () => {
|
||||||
|
mockGetAllManifestVersions.mockResolvedValue(["0.9.26", "0.9.25"]);
|
||||||
|
|
||||||
|
const version = await resolveVersion(
|
||||||
|
"^0.9.0",
|
||||||
|
"https://example.com/custom.ndjson",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(version).toBe("0.9.26");
|
||||||
|
expect(mockGetAllManifestVersions).toHaveBeenCalledWith(
|
||||||
|
"https://example.com/custom.ndjson",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("downloadVersionFromNdjson", () => {
|
||||||
|
it("fails when NDJSON metadata lookup fails", async () => {
|
||||||
|
mockGetArtifactFromNdjson.mockRejectedValue(
|
||||||
|
new Error("NDJSON unavailable"),
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
downloadVersionFromNdjson(
|
||||||
|
"unknown-linux-gnu",
|
||||||
|
"x86_64",
|
||||||
|
"0.9.26",
|
||||||
|
undefined,
|
||||||
|
"token",
|
||||||
|
),
|
||||||
|
).rejects.toThrow("NDJSON unavailable");
|
||||||
|
|
||||||
|
expect(mockDownloadTool).not.toHaveBeenCalled();
|
||||||
|
expect(mockValidateChecksum).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails when no matching artifact exists in NDJSON metadata", async () => {
|
||||||
|
mockGetArtifactFromNdjson.mockResolvedValue(undefined);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
downloadVersionFromNdjson(
|
||||||
|
"unknown-linux-gnu",
|
||||||
|
"x86_64",
|
||||||
|
"0.9.26",
|
||||||
|
undefined,
|
||||||
|
"token",
|
||||||
|
),
|
||||||
|
).rejects.toThrow(
|
||||||
|
"Could not find artifact for version 0.9.26, arch x86_64, platform unknown-linux-gnu in https://raw.githubusercontent.com/astral-sh/versions/main/v1/uv.ndjson .",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(mockDownloadTool).not.toHaveBeenCalled();
|
||||||
|
expect(mockValidateChecksum).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses built-in checksums for default NDJSON downloads", async () => {
|
||||||
|
mockGetArtifactFromNdjson.mockResolvedValue({
|
||||||
|
archiveFormat: "tar.gz",
|
||||||
|
sha256: "ndjson-checksum-that-should-be-ignored",
|
||||||
|
url: "https://example.com/uv.tar.gz",
|
||||||
|
});
|
||||||
|
|
||||||
|
await downloadVersionFromNdjson(
|
||||||
|
"unknown-linux-gnu",
|
||||||
|
"x86_64",
|
||||||
|
"0.9.26",
|
||||||
|
undefined,
|
||||||
|
"token",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(mockValidateChecksum).toHaveBeenCalledWith(
|
||||||
|
undefined,
|
||||||
|
"/tmp/downloaded",
|
||||||
|
"x86_64",
|
||||||
|
"unknown-linux-gnu",
|
||||||
|
"0.9.26",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("downloadVersionFromManifest", () => {
|
||||||
|
it("uses manifest-file checksum metadata when checksum input is unset", async () => {
|
||||||
|
mockGetManifestArtifact.mockResolvedValue({
|
||||||
|
archiveFormat: "tar.gz",
|
||||||
|
checksum: "manifest-checksum",
|
||||||
|
downloadUrl: "https://example.com/custom-uv.tar.gz",
|
||||||
|
});
|
||||||
|
|
||||||
|
await downloadVersionFromManifest(
|
||||||
|
"https://example.com/custom.ndjson",
|
||||||
|
"unknown-linux-gnu",
|
||||||
|
"x86_64",
|
||||||
|
"0.9.26",
|
||||||
|
"",
|
||||||
|
"token",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(mockValidateChecksum).toHaveBeenCalledWith(
|
||||||
|
"manifest-checksum",
|
||||||
|
"/tmp/downloaded",
|
||||||
|
"x86_64",
|
||||||
|
"unknown-linux-gnu",
|
||||||
|
"0.9.26",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("prefers checksum input over manifest-file checksum metadata", async () => {
|
||||||
|
mockGetManifestArtifact.mockResolvedValue({
|
||||||
|
archiveFormat: "tar.gz",
|
||||||
|
checksum: "manifest-checksum",
|
||||||
|
downloadUrl: "https://example.com/custom-uv.tar.gz",
|
||||||
|
});
|
||||||
|
|
||||||
|
await downloadVersionFromManifest(
|
||||||
|
"https://example.com/custom.ndjson",
|
||||||
|
"unknown-linux-gnu",
|
||||||
|
"x86_64",
|
||||||
|
"0.9.26",
|
||||||
|
"user-checksum",
|
||||||
|
"token",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(mockValidateChecksum).toHaveBeenCalledWith(
|
||||||
|
"user-checksum",
|
||||||
|
"/tmp/downloaded",
|
||||||
|
"x86_64",
|
||||||
|
"unknown-linux-gnu",
|
||||||
|
"0.9.26",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
136
__tests__/download/version-manifest.test.ts
Normal file
136
__tests__/download/version-manifest.test.ts
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
import { beforeEach, describe, expect, it, jest } from "@jest/globals";
|
||||||
|
|
||||||
|
const mockWarning = jest.fn();
|
||||||
|
|
||||||
|
jest.mock("@actions/core", () => ({
|
||||||
|
debug: jest.fn(),
|
||||||
|
info: jest.fn(),
|
||||||
|
warning: mockWarning,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: Mock requires flexible typing in tests.
|
||||||
|
const mockFetch = jest.fn<any>();
|
||||||
|
jest.mock("../../src/utils/fetch", () => ({
|
||||||
|
fetch: mockFetch,
|
||||||
|
}));
|
||||||
|
|
||||||
|
import {
|
||||||
|
clearManifestCache,
|
||||||
|
getAllVersions,
|
||||||
|
getLatestKnownVersion,
|
||||||
|
getManifestArtifact,
|
||||||
|
} from "../../src/download/version-manifest";
|
||||||
|
|
||||||
|
const legacyManifestResponse = JSON.stringify([
|
||||||
|
{
|
||||||
|
arch: "x86_64",
|
||||||
|
artifactName: "uv-x86_64-unknown-linux-gnu.tar.gz",
|
||||||
|
downloadUrl:
|
||||||
|
"https://example.com/releases/download/0.7.12-alpha.1/uv-x86_64-unknown-linux-gnu.tar.gz",
|
||||||
|
platform: "unknown-linux-gnu",
|
||||||
|
version: "0.7.12-alpha.1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arch: "x86_64",
|
||||||
|
artifactName: "uv-x86_64-unknown-linux-gnu.tar.gz",
|
||||||
|
downloadUrl:
|
||||||
|
"https://example.com/releases/download/0.7.13/uv-x86_64-unknown-linux-gnu.tar.gz",
|
||||||
|
platform: "unknown-linux-gnu",
|
||||||
|
version: "0.7.13",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const ndjsonManifestResponse = `{"version":"0.10.0","artifacts":[{"platform":"x86_64-unknown-linux-gnu","variant":"default","url":"https://example.com/releases/download/0.10.0/uv-x86_64-unknown-linux-gnu.tar.gz","archive_format":"tar.gz","sha256":"checksum-100"}]}
|
||||||
|
{"version":"0.9.30","artifacts":[{"platform":"x86_64-unknown-linux-gnu","variant":"default","url":"https://example.com/releases/download/0.9.30/uv-x86_64-unknown-linux-gnu.tar.gz","archive_format":"tar.gz","sha256":"checksum-0930"}]}`;
|
||||||
|
|
||||||
|
const multiVariantManifestResponse = `{"version":"0.10.0","artifacts":[{"platform":"x86_64-unknown-linux-gnu","variant":"managed-python","url":"https://example.com/releases/download/0.10.0/uv-x86_64-unknown-linux-gnu-managed-python.tar.gz","archive_format":"tar.gz","sha256":"checksum-managed"},{"platform":"x86_64-unknown-linux-gnu","variant":"default","url":"https://example.com/releases/download/0.10.0/uv-x86_64-unknown-linux-gnu-default.zip","archive_format":"zip","sha256":"checksum-default"}]}`;
|
||||||
|
|
||||||
|
function createMockResponse(
|
||||||
|
ok: boolean,
|
||||||
|
status: number,
|
||||||
|
statusText: string,
|
||||||
|
data: string,
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
ok,
|
||||||
|
status,
|
||||||
|
statusText,
|
||||||
|
text: async () => data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("version-manifest", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
clearManifestCache();
|
||||||
|
mockFetch.mockReset();
|
||||||
|
mockWarning.mockReset();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("supports the legacy JSON manifest format", async () => {
|
||||||
|
mockFetch.mockResolvedValue(
|
||||||
|
createMockResponse(true, 200, "OK", legacyManifestResponse),
|
||||||
|
);
|
||||||
|
|
||||||
|
const latest = await getLatestKnownVersion(
|
||||||
|
"https://example.com/legacy.json",
|
||||||
|
);
|
||||||
|
const artifact = await getManifestArtifact(
|
||||||
|
"https://example.com/legacy.json",
|
||||||
|
"0.7.13",
|
||||||
|
"x86_64",
|
||||||
|
"unknown-linux-gnu",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(latest).toBe("0.7.13");
|
||||||
|
expect(artifact).toEqual({
|
||||||
|
archiveFormat: undefined,
|
||||||
|
checksum: undefined,
|
||||||
|
downloadUrl:
|
||||||
|
"https://example.com/releases/download/0.7.13/uv-x86_64-unknown-linux-gnu.tar.gz",
|
||||||
|
});
|
||||||
|
expect(mockWarning).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("supports NDJSON manifests", async () => {
|
||||||
|
mockFetch.mockResolvedValue(
|
||||||
|
createMockResponse(true, 200, "OK", ndjsonManifestResponse),
|
||||||
|
);
|
||||||
|
|
||||||
|
const versions = await getAllVersions("https://example.com/custom.ndjson");
|
||||||
|
const artifact = await getManifestArtifact(
|
||||||
|
"https://example.com/custom.ndjson",
|
||||||
|
"0.10.0",
|
||||||
|
"x86_64",
|
||||||
|
"unknown-linux-gnu",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(versions).toEqual(["0.10.0", "0.9.30"]);
|
||||||
|
expect(artifact).toEqual({
|
||||||
|
archiveFormat: "tar.gz",
|
||||||
|
checksum: "checksum-100",
|
||||||
|
downloadUrl:
|
||||||
|
"https://example.com/releases/download/0.10.0/uv-x86_64-unknown-linux-gnu.tar.gz",
|
||||||
|
});
|
||||||
|
expect(mockWarning).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("prefers the default variant when a manifest contains multiple variants", async () => {
|
||||||
|
mockFetch.mockResolvedValue(
|
||||||
|
createMockResponse(true, 200, "OK", multiVariantManifestResponse),
|
||||||
|
);
|
||||||
|
|
||||||
|
const artifact = await getManifestArtifact(
|
||||||
|
"https://example.com/multi-variant.ndjson",
|
||||||
|
"0.10.0",
|
||||||
|
"x86_64",
|
||||||
|
"unknown-linux-gnu",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(artifact).toEqual({
|
||||||
|
archiveFormat: "zip",
|
||||||
|
checksum: "checksum-default",
|
||||||
|
downloadUrl:
|
||||||
|
"https://example.com/releases/download/0.10.0/uv-x86_64-unknown-linux-gnu-default.zip",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
169
__tests__/download/versions-client.test.ts
Normal file
169
__tests__/download/versions-client.test.ts
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
import { beforeEach, describe, expect, it, jest } from "@jest/globals";
|
||||||
|
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: Mock requires flexible typing in tests.
|
||||||
|
const mockFetch = jest.fn<any>();
|
||||||
|
jest.mock("../../src/utils/fetch", () => ({
|
||||||
|
fetch: mockFetch,
|
||||||
|
}));
|
||||||
|
|
||||||
|
import {
|
||||||
|
clearCache,
|
||||||
|
fetchVersionData,
|
||||||
|
getAllVersions,
|
||||||
|
getArtifact,
|
||||||
|
getLatestVersion,
|
||||||
|
parseVersionData,
|
||||||
|
} from "../../src/download/versions-client";
|
||||||
|
|
||||||
|
const sampleNdjsonResponse = `{"version":"0.9.26","artifacts":[{"platform":"aarch64-apple-darwin","variant":"default","url":"https://github.com/astral-sh/uv/releases/download/0.9.26/uv-aarch64-apple-darwin.tar.gz","archive_format":"tar.gz","sha256":"fcf0a9ea6599c6ae28a4c854ac6da76f2c889354d7c36ce136ef071f7ab9721f"},{"platform":"x86_64-pc-windows-msvc","variant":"default","url":"https://github.com/astral-sh/uv/releases/download/0.9.26/uv-x86_64-pc-windows-msvc.zip","archive_format":"zip","sha256":"eb02fd95d8e0eed462b4a67ecdd320d865b38c560bffcda9a0b87ec944bdf036"}]}
|
||||||
|
{"version":"0.9.25","artifacts":[{"platform":"aarch64-apple-darwin","variant":"default","url":"https://github.com/astral-sh/uv/releases/download/0.9.25/uv-aarch64-apple-darwin.tar.gz","archive_format":"tar.gz","sha256":"606b3c6949d971709f2526fa0d9f0fd23ccf60e09f117999b406b424af18a6a6"}]}`;
|
||||||
|
|
||||||
|
const multiVariantNdjsonResponse = `{"version":"0.9.26","artifacts":[{"platform":"aarch64-apple-darwin","variant":"python-managed","url":"https://github.com/astral-sh/uv/releases/download/0.9.26/uv-aarch64-apple-darwin-managed.tar.gz","archive_format":"tar.gz","sha256":"managed-checksum"},{"platform":"aarch64-apple-darwin","variant":"default","url":"https://github.com/astral-sh/uv/releases/download/0.9.26/uv-aarch64-apple-darwin.zip","archive_format":"zip","sha256":"default-checksum"}]}`;
|
||||||
|
|
||||||
|
function createMockResponse(
|
||||||
|
ok: boolean,
|
||||||
|
status: number,
|
||||||
|
statusText: string,
|
||||||
|
data: string,
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
ok,
|
||||||
|
status,
|
||||||
|
statusText,
|
||||||
|
text: async () => data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("versions-client", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
clearCache();
|
||||||
|
mockFetch.mockReset();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("fetchVersionData", () => {
|
||||||
|
it("should fetch and parse NDJSON data", async () => {
|
||||||
|
mockFetch.mockResolvedValue(
|
||||||
|
createMockResponse(true, 200, "OK", sampleNdjsonResponse),
|
||||||
|
);
|
||||||
|
|
||||||
|
const versions = await fetchVersionData();
|
||||||
|
|
||||||
|
expect(versions).toHaveLength(2);
|
||||||
|
expect(versions[0].version).toBe("0.9.26");
|
||||||
|
expect(versions[1].version).toBe("0.9.25");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should throw error on failed fetch", async () => {
|
||||||
|
mockFetch.mockResolvedValue(
|
||||||
|
createMockResponse(false, 500, "Internal Server Error", ""),
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(fetchVersionData()).rejects.toThrow(
|
||||||
|
"Failed to fetch version data: 500 Internal Server Error",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should cache results", async () => {
|
||||||
|
mockFetch.mockResolvedValue(
|
||||||
|
createMockResponse(true, 200, "OK", sampleNdjsonResponse),
|
||||||
|
);
|
||||||
|
|
||||||
|
await fetchVersionData();
|
||||||
|
await fetchVersionData();
|
||||||
|
|
||||||
|
expect(mockFetch).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("getLatestVersion", () => {
|
||||||
|
it("should return the first version (newest)", async () => {
|
||||||
|
mockFetch.mockResolvedValue(
|
||||||
|
createMockResponse(true, 200, "OK", sampleNdjsonResponse),
|
||||||
|
);
|
||||||
|
|
||||||
|
const latest = await getLatestVersion();
|
||||||
|
|
||||||
|
expect(latest).toBe("0.9.26");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("getAllVersions", () => {
|
||||||
|
it("should return all version strings", async () => {
|
||||||
|
mockFetch.mockResolvedValue(
|
||||||
|
createMockResponse(true, 200, "OK", sampleNdjsonResponse),
|
||||||
|
);
|
||||||
|
|
||||||
|
const versions = await getAllVersions();
|
||||||
|
|
||||||
|
expect(versions).toEqual(["0.9.26", "0.9.25"]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("getArtifact", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockFetch.mockResolvedValue(
|
||||||
|
createMockResponse(true, 200, "OK", sampleNdjsonResponse),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should find artifact by version and platform", async () => {
|
||||||
|
const artifact = await getArtifact("0.9.26", "aarch64", "apple-darwin");
|
||||||
|
|
||||||
|
expect(artifact).toEqual({
|
||||||
|
archiveFormat: "tar.gz",
|
||||||
|
sha256:
|
||||||
|
"fcf0a9ea6599c6ae28a4c854ac6da76f2c889354d7c36ce136ef071f7ab9721f",
|
||||||
|
url: "https://github.com/astral-sh/uv/releases/download/0.9.26/uv-aarch64-apple-darwin.tar.gz",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should find windows artifact", async () => {
|
||||||
|
const artifact = await getArtifact("0.9.26", "x86_64", "pc-windows-msvc");
|
||||||
|
|
||||||
|
expect(artifact).toEqual({
|
||||||
|
archiveFormat: "zip",
|
||||||
|
sha256:
|
||||||
|
"eb02fd95d8e0eed462b4a67ecdd320d865b38c560bffcda9a0b87ec944bdf036",
|
||||||
|
url: "https://github.com/astral-sh/uv/releases/download/0.9.26/uv-x86_64-pc-windows-msvc.zip",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should prefer the default variant when multiple artifacts share a platform", async () => {
|
||||||
|
mockFetch.mockResolvedValue(
|
||||||
|
createMockResponse(true, 200, "OK", multiVariantNdjsonResponse),
|
||||||
|
);
|
||||||
|
|
||||||
|
const artifact = await getArtifact("0.9.26", "aarch64", "apple-darwin");
|
||||||
|
|
||||||
|
expect(artifact).toEqual({
|
||||||
|
archiveFormat: "zip",
|
||||||
|
sha256: "default-checksum",
|
||||||
|
url: "https://github.com/astral-sh/uv/releases/download/0.9.26/uv-aarch64-apple-darwin.zip",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return undefined for unknown version", async () => {
|
||||||
|
const artifact = await getArtifact("0.0.1", "aarch64", "apple-darwin");
|
||||||
|
|
||||||
|
expect(artifact).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return undefined for unknown platform", async () => {
|
||||||
|
const artifact = await getArtifact(
|
||||||
|
"0.9.26",
|
||||||
|
"aarch64",
|
||||||
|
"unknown-linux-musl",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(artifact).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("parseVersionData", () => {
|
||||||
|
it("should throw for malformed NDJSON", () => {
|
||||||
|
expect(() =>
|
||||||
|
parseVersionData('{"version":"0.1.0"', "test-source"),
|
||||||
|
).toThrow("Failed to parse version data from test-source");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -9,5 +9,5 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["hatchling"]
|
requires = ["uv_build>=0.9.22,<0.10.0"]
|
||||||
build-backend = "hatchling.build"
|
build-backend = "uv_build"
|
||||||
|
|||||||
@@ -1,33 +1,9 @@
|
|||||||
version = 1
|
version = 1
|
||||||
requires-python = ">=3.12"
|
revision = 3
|
||||||
|
requires-python = ">=3.8, <=3.9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "old-python-constraint-project"
|
||||||
version = "0.6.2"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/23/f4/279d044f66b79261fd37df76bf72b64471afab5d3b7906a01499c4451910/ruff-0.6.2.tar.gz", hash = "sha256:239ee6beb9e91feb8e0ec384204a763f36cb53fb895a1a364618c6abb076b3be", size = 2460281 }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/72/4b/47dd7a69287afb4069fa42c198e899463605460a58120196711bfcf0446b/ruff-0.6.2-py3-none-linux_armv6l.whl", hash = "sha256:5c8cbc6252deb3ea840ad6a20b0f8583caab0c5ef4f9cca21adc5a92b8f79f3c", size = 9695871 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/ae/c3/8aac62ac4638c14a740ee76a755a925f2d0d04580ab790a9887accb729f6/ruff-0.6.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:17002fe241e76544448a8e1e6118abecbe8cd10cf68fde635dad480dba594570", size = 9459354 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/2f/cf/77fbd8d4617b9b9c503f9bffb8552c4e3ea1a58dc36975e7a9104ffb0f85/ruff-0.6.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3dbeac76ed13456f8158b8f4fe087bf87882e645c8e8b606dd17b0b66c2c1158", size = 9163871 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/05/1c/765192bab32b79efbb498b06f0b9dcb3629112b53b8777ae1d19b8209e09/ruff-0.6.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:094600ee88cda325988d3f54e3588c46de5c18dae09d683ace278b11f9d4d534", size = 10096250 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/08/d0/86f3cb0f6934c99f759c232984a5204d67a26745cad2d9edff6248adf7d2/ruff-0.6.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:316d418fe258c036ba05fbf7dfc1f7d3d4096db63431546163b472285668132b", size = 9475376 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/cd/cc/4c8d0e225b559a3fae6092ec310d7150d3b02b4669e9223f783ef64d82c0/ruff-0.6.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d72b8b3abf8a2d51b7b9944a41307d2f442558ccb3859bbd87e6ae9be1694a5d", size = 10295634 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/db/96/d2699cfb1bb5a01c68122af43454c76c31331e1c8a9bd97d653d7c82524b/ruff-0.6.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2aed7e243be68487aa8982e91c6e260982d00da3f38955873aecd5a9204b1d66", size = 11024941 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/8b/a9/6ecd66af8929e0f2a1ed308a4137f3521789f28f0eb97d32c2ca3aa7000c/ruff-0.6.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d371f7fc9cec83497fe7cf5eaf5b76e22a8efce463de5f775a1826197feb9df8", size = 10606894 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/e4/73/2ee4cd19f44992fedac1cc6db9e3d825966072f6dcbd4032f21cbd063170/ruff-0.6.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8f310d63af08f583363dfb844ba8f9417b558199c58a5999215082036d795a1", size = 11552886 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/60/4c/c0f1cd35ce4a93c54a6bb1ee6934a3a205fa02198dd076678193853ceea1/ruff-0.6.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7db6880c53c56addb8638fe444818183385ec85eeada1d48fc5abe045301b2f1", size = 10264945 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/c4/89/e45c9359b9cdd4245512ea2b9f2bb128a997feaa5f726fc9e8c7a66afadf/ruff-0.6.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1175d39faadd9a50718f478d23bfc1d4da5743f1ab56af81a2b6caf0a2394f23", size = 10100007 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/06/74/0bd4e0a7ed5f6908df87892f9bf60a2356c0fd74102d8097298bd9b4f346/ruff-0.6.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5b939f9c86d51635fe486585389f54582f0d65b8238e08c327c1534844b3bb9a", size = 9559267 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/54/03/3dc6dc9419f276f05805bf888c279e3e0b631284abd548d9e87cebb93aec/ruff-0.6.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d0d62ca91219f906caf9b187dea50d17353f15ec9bb15aae4a606cd697b49b4c", size = 9905304 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/5c/5b/d6a72a6a6bbf097c09de468326ef5fa1c9e7aa5e6e45979bc0d984b0dbe7/ruff-0.6.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7438a7288f9d67ed3c8ce4d059e67f7ed65e9fe3aa2ab6f5b4b3610e57e3cb56", size = 10341480 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/79/a9/0f2f21fe15ba537c46598f96aa9ae4a3d4b9ec64926664617ca6a8c772f4/ruff-0.6.2-py3-none-win32.whl", hash = "sha256:279d5f7d86696df5f9549b56b9b6a7f6c72961b619022b5b7999b15db392a4da", size = 7961901 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b0/80/fff12ffe11853d9f4ea3e5221e6dd2e93640a161c05c9579833e09ad40a7/ruff-0.6.2-py3-none-win_amd64.whl", hash = "sha256:d9f3469c7dd43cd22eb1c3fc16926fb8258d50cb1b216658a07be95dd117b0f2", size = 8783320 },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/56/91/577cdd64cce5e74d3f8b5ecb93f29566def569c741eb008aed4f331ef821/ruff-0.6.2-py3-none-win_arm64.whl", hash = "sha256:f28fcd2cd0e02bdf739297516d5643a945cc7caf09bd9bcb4d932540a5ea4fa9", size = 8225886 },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "uv-project"
|
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
@@ -35,4 +11,30 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [{ name = "ruff" }]
|
requires-dist = [{ name = "ruff", specifier = ">=0.6.2" }]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ruff"
|
||||||
|
version = "0.14.10"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/57/08/52232a877978dd8f9cf2aeddce3e611b40a63287dfca29b6b8da791f5e8d/ruff-0.14.10.tar.gz", hash = "sha256:9a2e830f075d1a42cd28420d7809ace390832a490ed0966fe373ba288e77aaf4", size = 5859763, upload-time = "2025-12-18T19:28:57.98Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/60/01/933704d69f3f05ee16ef11406b78881733c186fe14b6a46b05cfcaf6d3b2/ruff-0.14.10-py3-none-linux_armv6l.whl", hash = "sha256:7a3ce585f2ade3e1f29ec1b92df13e3da262178df8c8bdf876f48fa0e8316c49", size = 13527080, upload-time = "2025-12-18T19:29:25.642Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/58/a0349197a7dfa603ffb7f5b0470391efa79ddc327c1e29c4851e85b09cc5/ruff-0.14.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:674f9be9372907f7257c51f1d4fc902cb7cf014b9980152b802794317941f08f", size = 13797320, upload-time = "2025-12-18T19:29:02.571Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7b/82/36be59f00a6082e38c23536df4e71cdbc6af8d7c707eade97fcad5c98235/ruff-0.14.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d85713d522348837ef9df8efca33ccb8bd6fcfc86a2cde3ccb4bc9d28a18003d", size = 12918434, upload-time = "2025-12-18T19:28:51.202Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a6/00/45c62a7f7e34da92a25804f813ebe05c88aa9e0c25e5cb5a7d23dd7450e3/ruff-0.14.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6987ebe0501ae4f4308d7d24e2d0fe3d7a98430f5adfd0f1fead050a740a3a77", size = 13371961, upload-time = "2025-12-18T19:29:04.991Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/40/31/a5906d60f0405f7e57045a70f2d57084a93ca7425f22e1d66904769d1628/ruff-0.14.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:16a01dfb7b9e4eee556fbfd5392806b1b8550c9b4a9f6acd3dbe6812b193c70a", size = 13275629, upload-time = "2025-12-18T19:29:21.381Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/60/61c0087df21894cf9d928dc04bcd4fb10e8b2e8dca7b1a276ba2155b2002/ruff-0.14.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7165d31a925b7a294465fa81be8c12a0e9b60fb02bf177e79067c867e71f8b1f", size = 14029234, upload-time = "2025-12-18T19:29:00.132Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/44/84/77d911bee3b92348b6e5dab5a0c898d87084ea03ac5dc708f46d88407def/ruff-0.14.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c561695675b972effb0c0a45db233f2c816ff3da8dcfbe7dfc7eed625f218935", size = 15449890, upload-time = "2025-12-18T19:28:53.573Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e9/36/480206eaefa24a7ec321582dda580443a8f0671fdbf6b1c80e9c3e93a16a/ruff-0.14.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bb98fcbbc61725968893682fd4df8966a34611239c9fd07a1f6a07e7103d08e", size = 15123172, upload-time = "2025-12-18T19:29:23.453Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5c/38/68e414156015ba80cef5473d57919d27dfb62ec804b96180bafdeaf0e090/ruff-0.14.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f24b47993a9d8cb858429e97bdf8544c78029f09b520af615c1d261bf827001d", size = 14460260, upload-time = "2025-12-18T19:29:27.808Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/19/9e050c0dca8aba824d67cc0db69fb459c28d8cd3f6855b1405b3f29cc91d/ruff-0.14.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59aabd2e2c4fd614d2862e7939c34a532c04f1084476d6833dddef4afab87e9f", size = 14229978, upload-time = "2025-12-18T19:29:11.32Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/51/eb/e8dd1dd6e05b9e695aa9dd420f4577debdd0f87a5ff2fedda33c09e9be8c/ruff-0.14.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:213db2b2e44be8625002dbea33bb9c60c66ea2c07c084a00d55732689d697a7f", size = 14338036, upload-time = "2025-12-18T19:29:09.184Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6a/12/f3e3a505db7c19303b70af370d137795fcfec136d670d5de5391e295c134/ruff-0.14.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b914c40ab64865a17a9a5b67911d14df72346a634527240039eb3bd650e5979d", size = 13264051, upload-time = "2025-12-18T19:29:13.431Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/08/64/8c3a47eaccfef8ac20e0484e68e0772013eb85802f8a9f7603ca751eb166/ruff-0.14.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1484983559f026788e3a5c07c81ef7d1e97c1c78ed03041a18f75df104c45405", size = 13283998, upload-time = "2025-12-18T19:29:06.994Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/12/84/534a5506f4074e5cc0529e5cd96cfc01bb480e460c7edf5af70d2bcae55e/ruff-0.14.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c70427132db492d25f982fffc8d6c7535cc2fd2c83fc8888f05caaa248521e60", size = 13601891, upload-time = "2025-12-18T19:28:55.811Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0d/1e/14c916087d8598917dbad9b2921d340f7884824ad6e9c55de948a93b106d/ruff-0.14.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5bcf45b681e9f1ee6445d317ce1fa9d6cba9a6049542d1c3d5b5958986be8830", size = 14336660, upload-time = "2025-12-18T19:29:16.531Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/1c/d7b67ab43f30013b47c12b42d1acd354c195351a3f7a1d67f59e54227ede/ruff-0.14.10-py3-none-win32.whl", hash = "sha256:104c49fc7ab73f3f3a758039adea978869a918f31b73280db175b43a2d9b51d6", size = 13196187, upload-time = "2025-12-18T19:29:19.006Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/9c/896c862e13886fae2af961bef3e6312db9ebc6adc2b156fe95e615dee8c1/ruff-0.14.10-py3-none-win_amd64.whl", hash = "sha256:466297bd73638c6bdf06485683e812db1c00c7ac96d4ddd0294a338c62fdc154", size = 14661283, upload-time = "2025-12-18T19:29:30.16Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/74/31/b0e29d572670dca3674eeee78e418f20bdf97fa8aa9ea71380885e175ca0/ruff-0.14.10-py3-none-win_arm64.whl", hash = "sha256:e51d046cf6dda98a4633b8a8a771451107413b0f07183b2bef03f075599e44e6", size = 13729839, upload-time = "2025-12-18T19:28:48.636Z" },
|
||||||
|
]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ jest.mock("@actions/core", () => {
|
|||||||
(name: string) => (mockInputs[name] ?? "") === "true",
|
(name: string) => (mockInputs[name] ?? "") === "true",
|
||||||
),
|
),
|
||||||
getInput: jest.fn((name: string) => mockInputs[name] ?? ""),
|
getInput: jest.fn((name: string) => mockInputs[name] ?? ""),
|
||||||
|
warning: jest.fn(),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@ const ORIGINAL_HOME = process.env.HOME;
|
|||||||
describe("cacheDependencyGlob", () => {
|
describe("cacheDependencyGlob", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.resetModules();
|
jest.resetModules();
|
||||||
|
jest.clearAllMocks();
|
||||||
mockInputs = {};
|
mockInputs = {};
|
||||||
process.env.HOME = "/home/testuser";
|
process.env.HOME = "/home/testuser";
|
||||||
});
|
});
|
||||||
@@ -84,3 +86,125 @@ describe("cacheDependencyGlob", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("tool directories", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.resetModules();
|
||||||
|
jest.clearAllMocks();
|
||||||
|
mockInputs = {};
|
||||||
|
process.env.HOME = "/home/testuser";
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
process.env.HOME = ORIGINAL_HOME;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("expands tilde for tool-bin-dir and tool-dir", async () => {
|
||||||
|
mockInputs["working-directory"] = "/workspace";
|
||||||
|
mockInputs["tool-bin-dir"] = "~/tool-bin-dir";
|
||||||
|
mockInputs["tool-dir"] = "~/tool-dir";
|
||||||
|
|
||||||
|
const { toolBinDir, toolDir } = await import("../../src/utils/inputs");
|
||||||
|
|
||||||
|
expect(toolBinDir).toBe("/home/testuser/tool-bin-dir");
|
||||||
|
expect(toolDir).toBe("/home/testuser/tool-dir");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("cacheLocalPath", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.resetModules();
|
||||||
|
jest.clearAllMocks();
|
||||||
|
mockInputs = {};
|
||||||
|
process.env.HOME = "/home/testuser";
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
process.env.HOME = ORIGINAL_HOME;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("expands tilde in cache-local-path", async () => {
|
||||||
|
mockInputs["working-directory"] = "/workspace";
|
||||||
|
mockInputs["cache-local-path"] = "~/uv-cache/cache-local-path";
|
||||||
|
|
||||||
|
const { CacheLocalSource, cacheLocalPath } = await import(
|
||||||
|
"../../src/utils/inputs"
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(cacheLocalPath).toEqual({
|
||||||
|
path: "/home/testuser/uv-cache/cache-local-path",
|
||||||
|
source: CacheLocalSource.Input,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("venvPath", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.resetModules();
|
||||||
|
jest.clearAllMocks();
|
||||||
|
mockInputs = {};
|
||||||
|
process.env.HOME = "/home/testuser";
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
process.env.HOME = ORIGINAL_HOME;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("defaults to .venv in the working directory", async () => {
|
||||||
|
mockInputs["working-directory"] = "/workspace";
|
||||||
|
const { venvPath } = await import("../../src/utils/inputs");
|
||||||
|
expect(venvPath).toBe("/workspace/.venv");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("resolves a relative venv-path", async () => {
|
||||||
|
mockInputs["working-directory"] = "/workspace";
|
||||||
|
mockInputs["activate-environment"] = "true";
|
||||||
|
mockInputs["venv-path"] = "custom-venv";
|
||||||
|
const { venvPath } = await import("../../src/utils/inputs");
|
||||||
|
expect(venvPath).toBe("/workspace/custom-venv");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("normalizes venv-path with trailing slash", async () => {
|
||||||
|
mockInputs["working-directory"] = "/workspace";
|
||||||
|
mockInputs["activate-environment"] = "true";
|
||||||
|
mockInputs["venv-path"] = "custom-venv/";
|
||||||
|
const { venvPath } = await import("../../src/utils/inputs");
|
||||||
|
expect(venvPath).toBe("/workspace/custom-venv");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps an absolute venv-path unchanged", async () => {
|
||||||
|
mockInputs["working-directory"] = "/workspace";
|
||||||
|
mockInputs["activate-environment"] = "true";
|
||||||
|
mockInputs["venv-path"] = "/tmp/custom-venv";
|
||||||
|
const { venvPath } = await import("../../src/utils/inputs");
|
||||||
|
expect(venvPath).toBe("/tmp/custom-venv");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("expands tilde in venv-path", async () => {
|
||||||
|
mockInputs["working-directory"] = "/workspace";
|
||||||
|
mockInputs["activate-environment"] = "true";
|
||||||
|
mockInputs["venv-path"] = "~/.venv";
|
||||||
|
const { venvPath } = await import("../../src/utils/inputs");
|
||||||
|
expect(venvPath).toBe("/home/testuser/.venv");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("warns when venv-path is set but activate-environment is false", async () => {
|
||||||
|
mockInputs["working-directory"] = "/workspace";
|
||||||
|
mockInputs["venv-path"] = "custom-venv";
|
||||||
|
|
||||||
|
const { activateEnvironment, venvPath } = await import(
|
||||||
|
"../../src/utils/inputs"
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(activateEnvironment).toBe(false);
|
||||||
|
expect(venvPath).toBe("/workspace/custom-venv");
|
||||||
|
|
||||||
|
const mockedCore = jest.requireMock("@actions/core") as {
|
||||||
|
warning: jest.Mock;
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(mockedCore.warning).toHaveBeenCalledWith(
|
||||||
|
"venv-path is only used when activate-environment is true",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
77
action-types.yml
Normal file
77
action-types.yml
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# See https://github.com/typesafegithub/github-actions-typing
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
type: string
|
||||||
|
version-file:
|
||||||
|
type: string
|
||||||
|
python-version:
|
||||||
|
type: string
|
||||||
|
activate-environment:
|
||||||
|
type: boolean
|
||||||
|
venv-path:
|
||||||
|
type: string
|
||||||
|
working-directory:
|
||||||
|
type: string
|
||||||
|
checksum:
|
||||||
|
type: string
|
||||||
|
github-token:
|
||||||
|
type: string
|
||||||
|
enable-cache:
|
||||||
|
type: enum
|
||||||
|
allowed-values:
|
||||||
|
- "true"
|
||||||
|
- "false"
|
||||||
|
- auto
|
||||||
|
cache-dependency-glob:
|
||||||
|
type: list
|
||||||
|
separator: "\n"
|
||||||
|
list-item:
|
||||||
|
type: string
|
||||||
|
restore-cache:
|
||||||
|
type: boolean
|
||||||
|
save-cache:
|
||||||
|
type: boolean
|
||||||
|
cache-suffix:
|
||||||
|
type: string
|
||||||
|
cache-local-path:
|
||||||
|
type: string
|
||||||
|
prune-cache:
|
||||||
|
type: boolean
|
||||||
|
cache-python:
|
||||||
|
type: boolean
|
||||||
|
ignore-nothing-to-cache:
|
||||||
|
type: boolean
|
||||||
|
ignore-empty-workdir:
|
||||||
|
type: boolean
|
||||||
|
tool-dir:
|
||||||
|
type: string
|
||||||
|
tool-bin-dir:
|
||||||
|
type: string
|
||||||
|
manifest-file:
|
||||||
|
type: string
|
||||||
|
add-problem-matchers:
|
||||||
|
type: boolean
|
||||||
|
resolution-strategy:
|
||||||
|
type: enum
|
||||||
|
allowed-values:
|
||||||
|
- highest
|
||||||
|
- lowest
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
uv-version:
|
||||||
|
type: string
|
||||||
|
uv-path:
|
||||||
|
type: string
|
||||||
|
uvx-path:
|
||||||
|
type: string
|
||||||
|
cache-hit:
|
||||||
|
type: boolean
|
||||||
|
cache-key:
|
||||||
|
type: string
|
||||||
|
venv:
|
||||||
|
type: string
|
||||||
|
python-version:
|
||||||
|
type: string
|
||||||
|
python-cache-hit:
|
||||||
|
type: boolean
|
||||||
13
action.yml
13
action.yml
@@ -15,6 +15,9 @@ inputs:
|
|||||||
activate-environment:
|
activate-environment:
|
||||||
description: "Use uv venv to activate a venv ready to be used by later steps. "
|
description: "Use uv venv to activate a venv ready to be used by later steps. "
|
||||||
default: "false"
|
default: "false"
|
||||||
|
venv-path:
|
||||||
|
description: "Custom path for the virtual environment when using activate-environment. Defaults to '.venv' in the working directory."
|
||||||
|
default: ""
|
||||||
working-directory:
|
working-directory:
|
||||||
description: "The directory to execute all commands in and look for files such as pyproject.toml"
|
description: "The directory to execute all commands in and look for files such as pyproject.toml"
|
||||||
default: ${{ github.workspace }}
|
default: ${{ github.workspace }}
|
||||||
@@ -23,7 +26,7 @@ inputs:
|
|||||||
required: false
|
required: false
|
||||||
github-token:
|
github-token:
|
||||||
description:
|
description:
|
||||||
"Used to increase the rate limit when retrieving versions and downloading uv."
|
"Used when downloading uv from GitHub releases."
|
||||||
required: false
|
required: false
|
||||||
default: ${{ github.token }}
|
default: ${{ github.token }}
|
||||||
enable-cache:
|
enable-cache:
|
||||||
@@ -72,7 +75,7 @@ inputs:
|
|||||||
description: "Custom path to set UV_TOOL_BIN_DIR to."
|
description: "Custom path to set UV_TOOL_BIN_DIR to."
|
||||||
required: false
|
required: false
|
||||||
manifest-file:
|
manifest-file:
|
||||||
description: "URL to the manifest file containing available versions and download URLs."
|
description: "URL to a custom manifest file. Supports the astral-sh/versions NDJSON format and the legacy JSON array format (deprecated)."
|
||||||
required: false
|
required: false
|
||||||
add-problem-matchers:
|
add-problem-matchers:
|
||||||
description: "Add problem matchers."
|
description: "Add problem matchers."
|
||||||
@@ -89,8 +92,14 @@ outputs:
|
|||||||
description: "The path to the installed uvx binary."
|
description: "The path to the installed uvx binary."
|
||||||
cache-hit:
|
cache-hit:
|
||||||
description: "A boolean value to indicate a cache entry was found"
|
description: "A boolean value to indicate a cache entry was found"
|
||||||
|
cache-key:
|
||||||
|
description: "The cache key used for storing/restoring the cache"
|
||||||
venv:
|
venv:
|
||||||
description: "Path to the activated venv if activate-environment is true"
|
description: "Path to the activated venv if activate-environment is true"
|
||||||
|
python-version:
|
||||||
|
description: "The Python version that was set."
|
||||||
|
python-cache-hit:
|
||||||
|
description: "A boolean value to indicate the Python cache entry was found"
|
||||||
runs:
|
runs:
|
||||||
using: "node24"
|
using: "node24"
|
||||||
main: "dist/setup/index.js"
|
main: "dist/setup/index.js"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://biomejs.dev/schemas/2.3.0/schema.json",
|
"$schema": "https://biomejs.dev/schemas/2.3.7/schema.json",
|
||||||
"assist": {
|
"assist": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"source": {
|
"source": {
|
||||||
@@ -18,7 +18,8 @@
|
|||||||
"!**/node_modules",
|
"!**/node_modules",
|
||||||
"!**/package*.json",
|
"!**/package*.json",
|
||||||
"!**/known-checksums.*"
|
"!**/known-checksums.*"
|
||||||
]
|
],
|
||||||
|
"maxSize": 2097152
|
||||||
},
|
},
|
||||||
"formatter": {
|
"formatter": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
|||||||
399
dist/save-cache/index.js
generated
vendored
399
dist/save-cache/index.js
generated
vendored
@@ -90599,42 +90599,52 @@ var __importStar = (this && this.__importStar) || (function () {
|
|||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.STATE_CACHE_MATCHED_KEY = exports.STATE_CACHE_KEY = void 0;
|
exports.STATE_PYTHON_CACHE_MATCHED_KEY = exports.STATE_CACHE_MATCHED_KEY = exports.STATE_CACHE_KEY = void 0;
|
||||||
exports.restoreCache = restoreCache;
|
exports.restoreCache = restoreCache;
|
||||||
const cache = __importStar(__nccwpck_require__(5116));
|
const cache = __importStar(__nccwpck_require__(5116));
|
||||||
const core = __importStar(__nccwpck_require__(7484));
|
const core = __importStar(__nccwpck_require__(7484));
|
||||||
const exec = __importStar(__nccwpck_require__(5236));
|
|
||||||
const hash_files_1 = __nccwpck_require__(9660);
|
const hash_files_1 = __nccwpck_require__(9660);
|
||||||
const inputs_1 = __nccwpck_require__(9612);
|
const inputs_1 = __nccwpck_require__(9612);
|
||||||
const platforms_1 = __nccwpck_require__(8361);
|
const platforms_1 = __nccwpck_require__(8361);
|
||||||
exports.STATE_CACHE_KEY = "cache-key";
|
exports.STATE_CACHE_KEY = "cache-key";
|
||||||
exports.STATE_CACHE_MATCHED_KEY = "cache-matched-key";
|
exports.STATE_CACHE_MATCHED_KEY = "cache-matched-key";
|
||||||
const CACHE_VERSION = "1";
|
exports.STATE_PYTHON_CACHE_MATCHED_KEY = "python-cache-matched-key";
|
||||||
async function restoreCache() {
|
const CACHE_VERSION = "2";
|
||||||
const cacheKey = await computeKeys();
|
async function restoreCache(pythonVersion) {
|
||||||
|
const cacheKey = await computeKeys(pythonVersion);
|
||||||
core.saveState(exports.STATE_CACHE_KEY, cacheKey);
|
core.saveState(exports.STATE_CACHE_KEY, cacheKey);
|
||||||
|
core.setOutput("cache-key", cacheKey);
|
||||||
if (!inputs_1.restoreCache) {
|
if (!inputs_1.restoreCache) {
|
||||||
core.info("restore-cache is false. Skipping restore cache step.");
|
core.info("restore-cache is false. Skipping restore cache step.");
|
||||||
|
core.setOutput("python-cache-hit", false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let matchedKey;
|
if (inputs_1.cacheLocalPath === undefined) {
|
||||||
core.info(`Trying to restore uv cache from GitHub Actions cache with key: ${cacheKey}`);
|
throw new Error("cache-local-path is not set. Cannot restore cache without a valid cache path.");
|
||||||
const cachePaths = [inputs_1.cacheLocalPath];
|
|
||||||
if (inputs_1.cachePython) {
|
|
||||||
cachePaths.push(inputs_1.pythonDir);
|
|
||||||
}
|
}
|
||||||
|
await restoreCacheFromKey(cacheKey, inputs_1.cacheLocalPath.path, exports.STATE_CACHE_MATCHED_KEY, "cache-hit");
|
||||||
|
if (inputs_1.cachePython) {
|
||||||
|
await restoreCacheFromKey(`${cacheKey}-python`, inputs_1.pythonDir, exports.STATE_PYTHON_CACHE_MATCHED_KEY, "python-cache-hit");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
core.setOutput("python-cache-hit", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function restoreCacheFromKey(cacheKey, cachePath, stateKey, outputKey) {
|
||||||
|
core.info(`Trying to restore cache from GitHub Actions cache with key: ${cacheKey}`);
|
||||||
|
let matchedKey;
|
||||||
try {
|
try {
|
||||||
matchedKey = await cache.restoreCache(cachePaths, cacheKey);
|
matchedKey = await cache.restoreCache([cachePath], cacheKey);
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
const message = err.message;
|
const message = err.message;
|
||||||
core.warning(message);
|
core.warning(message);
|
||||||
core.setOutput("cache-hit", false);
|
core.setOutput(outputKey, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
handleMatchResult(matchedKey, cacheKey);
|
handleMatchResult(matchedKey, cacheKey, stateKey, outputKey);
|
||||||
}
|
}
|
||||||
async function computeKeys() {
|
async function computeKeys(pythonVersion) {
|
||||||
let cacheDependencyPathHash = "-";
|
let cacheDependencyPathHash = "-";
|
||||||
if (inputs_1.cacheDependencyGlob !== "") {
|
if (inputs_1.cacheDependencyGlob !== "") {
|
||||||
core.info(`Searching files using cache dependency glob: ${inputs_1.cacheDependencyGlob.split("\n").join(",")}`);
|
core.info(`Searching files using cache dependency glob: ${inputs_1.cacheDependencyGlob.split("\n").join(",")}`);
|
||||||
@@ -90647,49 +90657,22 @@ async function computeKeys() {
|
|||||||
cacheDependencyPathHash = "-no-dependency-glob";
|
cacheDependencyPathHash = "-no-dependency-glob";
|
||||||
}
|
}
|
||||||
const suffix = inputs_1.cacheSuffix ? `-${inputs_1.cacheSuffix}` : "";
|
const suffix = inputs_1.cacheSuffix ? `-${inputs_1.cacheSuffix}` : "";
|
||||||
const pythonVersion = await getPythonVersion();
|
const version = pythonVersion ?? "unknown";
|
||||||
const platform = await (0, platforms_1.getPlatform)();
|
const platform = await (0, platforms_1.getPlatform)();
|
||||||
|
const osNameVersion = (0, platforms_1.getOSNameVersion)();
|
||||||
const pruned = inputs_1.pruneCache ? "-pruned" : "";
|
const pruned = inputs_1.pruneCache ? "-pruned" : "";
|
||||||
const python = inputs_1.cachePython ? "-py" : "";
|
const python = inputs_1.cachePython ? "-py" : "";
|
||||||
return `setup-uv-${CACHE_VERSION}-${(0, platforms_1.getArch)()}-${platform}-${pythonVersion}${pruned}${python}${cacheDependencyPathHash}${suffix}`;
|
return `setup-uv-${CACHE_VERSION}-${(0, platforms_1.getArch)()}-${platform}-${osNameVersion}-${version}${pruned}${python}${cacheDependencyPathHash}${suffix}`;
|
||||||
}
|
}
|
||||||
async function getPythonVersion() {
|
function handleMatchResult(matchedKey, primaryKey, stateKey, outputKey) {
|
||||||
if (inputs_1.pythonVersion !== "") {
|
|
||||||
return inputs_1.pythonVersion;
|
|
||||||
}
|
|
||||||
let output = "";
|
|
||||||
const options = {
|
|
||||||
listeners: {
|
|
||||||
stdout: (data) => {
|
|
||||||
output += data.toString();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
silent: !core.isDebug(),
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
const execArgs = ["python", "find", "--directory", inputs_1.workingDirectory];
|
|
||||||
await exec.exec("uv", execArgs, options);
|
|
||||||
const pythonPath = output.trim();
|
|
||||||
output = "";
|
|
||||||
await exec.exec(pythonPath, ["--version"], options);
|
|
||||||
// output is like "Python 3.8.10"
|
|
||||||
return output.split(" ")[1].trim();
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
const err = error;
|
|
||||||
core.debug(`Failed to get python version from uv. Error: ${err.message}`);
|
|
||||||
return "unknown";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function handleMatchResult(matchedKey, primaryKey) {
|
|
||||||
if (!matchedKey) {
|
if (!matchedKey) {
|
||||||
core.info(`No GitHub Actions cache found for key: ${primaryKey}`);
|
core.info(`No GitHub Actions cache found for key: ${primaryKey}`);
|
||||||
core.setOutput("cache-hit", false);
|
core.setOutput(outputKey, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
core.saveState(exports.STATE_CACHE_MATCHED_KEY, matchedKey);
|
core.saveState(stateKey, matchedKey);
|
||||||
core.info(`uv cache restored from GitHub Actions cache with key: ${matchedKey}`);
|
core.info(`cache restored from GitHub Actions cache with key: ${matchedKey}`);
|
||||||
core.setOutput("cache-hit", true);
|
core.setOutput(outputKey, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -90839,6 +90822,8 @@ async function run() {
|
|||||||
else {
|
else {
|
||||||
core.info("save-cache is false. Skipping save cache step.");
|
core.info("save-cache is false. Skipping save cache step.");
|
||||||
}
|
}
|
||||||
|
// https://github.com/nodejs/node/issues/56645#issuecomment-3077594952
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||||
// node will stay alive if any promises are not resolved,
|
// node will stay alive if any promises are not resolved,
|
||||||
// which is a possibility if HTTP requests are dangling
|
// which is a possibility if HTTP requests are dangling
|
||||||
// due to retries or timeouts. We know that if we got here
|
// due to retries or timeouts. We know that if we got here
|
||||||
@@ -90861,43 +90846,32 @@ async function saveCache() {
|
|||||||
}
|
}
|
||||||
if (matchedKey === cacheKey) {
|
if (matchedKey === cacheKey) {
|
||||||
core.info(`Cache hit occurred on key ${cacheKey}, not saving cache.`);
|
core.info(`Cache hit occurred on key ${cacheKey}, not saving cache.`);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (inputs_1.pruneCache) {
|
else {
|
||||||
await pruneCache();
|
if (inputs_1.pruneCache) {
|
||||||
}
|
await pruneCache();
|
||||||
let actualCachePath = inputs_1.cacheLocalPath;
|
|
||||||
if (process.env.UV_CACHE_DIR && process.env.UV_CACHE_DIR !== inputs_1.cacheLocalPath) {
|
|
||||||
core.warning(`The environment variable UV_CACHE_DIR has been changed to "${process.env.UV_CACHE_DIR}", by an action or step running after astral-sh/setup-uv. This can lead to unexpected behavior. If you expected this to happen set the cache-local-path input to "${process.env.UV_CACHE_DIR}" instead of "${inputs_1.cacheLocalPath}".`);
|
|
||||||
actualCachePath = process.env.UV_CACHE_DIR;
|
|
||||||
}
|
|
||||||
core.info(`Saving cache path: ${actualCachePath}`);
|
|
||||||
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) {
|
|
||||||
core.info(`Including Python cache path: ${inputs_1.pythonDir}`);
|
|
||||||
if (!fs.existsSync(inputs_1.pythonDir) && !inputs_1.ignoreNothingToCache) {
|
|
||||||
throw new Error(`Python cache path ${inputs_1.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(inputs_1.pythonDir);
|
const actualCachePath = getUvCachePath();
|
||||||
}
|
if (!fs.existsSync(actualCachePath)) {
|
||||||
core.info(`Final cache paths: ${cachePaths.join(", ")}`);
|
if (inputs_1.ignoreNothingToCache) {
|
||||||
try {
|
core.info("No cacheable uv cache paths were found. Ignoring because ignore-nothing-to-cache is enabled.");
|
||||||
await cache.saveCache(cachePaths, cacheKey);
|
}
|
||||||
core.info(`cache saved with the key: ${cacheKey}`);
|
else {
|
||||||
}
|
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.`);
|
||||||
catch (e) {
|
}
|
||||||
if (e instanceof Error &&
|
|
||||||
e.message ===
|
|
||||||
"Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.") {
|
|
||||||
core.info("No cacheable paths were found. Ignoring because ignore-nothing-to-save is enabled.");
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw e;
|
await saveCacheToKey(cacheKey, actualCachePath, restore_cache_1.STATE_CACHE_MATCHED_KEY, "uv cache");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (inputs_1.cachePython) {
|
||||||
|
if (!fs.existsSync(inputs_1.pythonDir)) {
|
||||||
|
core.warning(`Python cache path ${inputs_1.pythonDir} does not exist on disk. Skipping Python cache save because no managed Python installation was found. If you want uv to install managed Python instead of using a system interpreter, set UV_PYTHON_PREFERENCE=only-managed.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const pythonCacheKey = `${cacheKey}-python`;
|
||||||
|
await saveCacheToKey(pythonCacheKey, inputs_1.pythonDir, restore_cache_1.STATE_PYTHON_CACHE_MATCHED_KEY, "Python cache");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
async function pruneCache() {
|
async function pruneCache() {
|
||||||
const forceSupported = pep440.gte(core.getState(constants_1.STATE_UV_VERSION), "0.8.24");
|
const forceSupported = pep440.gte(core.getState(constants_1.STATE_UV_VERSION), "0.8.24");
|
||||||
@@ -90912,6 +90886,27 @@ async function pruneCache() {
|
|||||||
const uvPath = core.getState(constants_1.STATE_UV_PATH);
|
const uvPath = core.getState(constants_1.STATE_UV_PATH);
|
||||||
await exec.exec(uvPath, execArgs, options);
|
await exec.exec(uvPath, execArgs, options);
|
||||||
}
|
}
|
||||||
|
function getUvCachePath() {
|
||||||
|
if (inputs_1.cacheLocalPath === undefined) {
|
||||||
|
throw new Error("cache-local-path is not set. Cannot save cache without a valid cache path.");
|
||||||
|
}
|
||||||
|
if (process.env.UV_CACHE_DIR &&
|
||||||
|
process.env.UV_CACHE_DIR !== inputs_1.cacheLocalPath.path) {
|
||||||
|
core.warning(`The environment variable UV_CACHE_DIR has been changed to "${process.env.UV_CACHE_DIR}", by an action or step running after astral-sh/setup-uv. This can lead to unexpected behavior. If you expected this to happen set the cache-local-path input to "${process.env.UV_CACHE_DIR}" instead of "${inputs_1.cacheLocalPath.path}".`);
|
||||||
|
return process.env.UV_CACHE_DIR;
|
||||||
|
}
|
||||||
|
return inputs_1.cacheLocalPath.path;
|
||||||
|
}
|
||||||
|
async function saveCacheToKey(cacheKey, cachePath, stateKey, cacheName) {
|
||||||
|
const matchedKey = core.getState(stateKey);
|
||||||
|
if (matchedKey === cacheKey) {
|
||||||
|
core.info(`${cacheName} hit occurred on key ${cacheKey}, not saving cache.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
core.info(`Including ${cacheName} path: ${cachePath}`);
|
||||||
|
await cache.saveCache([cachePath], cacheKey);
|
||||||
|
core.info(`${cacheName} saved with key: ${cacheKey}`);
|
||||||
|
}
|
||||||
run();
|
run();
|
||||||
|
|
||||||
|
|
||||||
@@ -90984,12 +90979,11 @@ function getConfigValueFromTomlFile(filePath, key) {
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.STATE_UV_VERSION = exports.STATE_UV_PATH = exports.TOOL_CACHE_NAME = exports.OWNER = exports.REPO = void 0;
|
exports.VERSIONS_NDJSON_URL = exports.STATE_UV_VERSION = exports.STATE_UV_PATH = exports.TOOL_CACHE_NAME = void 0;
|
||||||
exports.REPO = "uv";
|
|
||||||
exports.OWNER = "astral-sh";
|
|
||||||
exports.TOOL_CACHE_NAME = "uv";
|
exports.TOOL_CACHE_NAME = "uv";
|
||||||
exports.STATE_UV_PATH = "uv-path";
|
exports.STATE_UV_PATH = "uv-path";
|
||||||
exports.STATE_UV_VERSION = "uv-version";
|
exports.STATE_UV_VERSION = "uv-version";
|
||||||
|
exports.VERSIONS_NDJSON_URL = "https://raw.githubusercontent.com/astral-sh/versions/main/v1/uv.ndjson";
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
@@ -91036,16 +91030,24 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.resolutionStrategy = exports.addProblemMatchers = exports.manifestFile = exports.githubToken = exports.pythonDir = 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.resolutionStrategy = exports.addProblemMatchers = exports.manifestFile = exports.githubToken = exports.pythonDir = 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.venvPath = exports.activateEnvironment = exports.pythonVersion = exports.versionFile = exports.version = exports.workingDirectory = exports.CacheLocalSource = void 0;
|
||||||
exports.getUvPythonDir = getUvPythonDir;
|
exports.getUvPythonDir = getUvPythonDir;
|
||||||
const node_path_1 = __importDefault(__nccwpck_require__(6760));
|
const node_path_1 = __importDefault(__nccwpck_require__(6760));
|
||||||
const core = __importStar(__nccwpck_require__(7484));
|
const core = __importStar(__nccwpck_require__(7484));
|
||||||
const config_file_1 = __nccwpck_require__(7846);
|
const config_file_1 = __nccwpck_require__(7846);
|
||||||
|
var CacheLocalSource;
|
||||||
|
(function (CacheLocalSource) {
|
||||||
|
CacheLocalSource[CacheLocalSource["Input"] = 0] = "Input";
|
||||||
|
CacheLocalSource[CacheLocalSource["Config"] = 1] = "Config";
|
||||||
|
CacheLocalSource[CacheLocalSource["Env"] = 2] = "Env";
|
||||||
|
CacheLocalSource[CacheLocalSource["Default"] = 3] = "Default";
|
||||||
|
})(CacheLocalSource || (exports.CacheLocalSource = CacheLocalSource = {}));
|
||||||
exports.workingDirectory = core.getInput("working-directory");
|
exports.workingDirectory = core.getInput("working-directory");
|
||||||
exports.version = core.getInput("version");
|
exports.version = core.getInput("version");
|
||||||
exports.versionFile = getVersionFile();
|
exports.versionFile = getVersionFile();
|
||||||
exports.pythonVersion = core.getInput("python-version");
|
exports.pythonVersion = core.getInput("python-version");
|
||||||
exports.activateEnvironment = core.getBooleanInput("activate-environment");
|
exports.activateEnvironment = core.getBooleanInput("activate-environment");
|
||||||
|
exports.venvPath = getVenvPath();
|
||||||
exports.checkSum = core.getInput("checksum");
|
exports.checkSum = core.getInput("checksum");
|
||||||
exports.enableCache = getEnableCache();
|
exports.enableCache = getEnableCache();
|
||||||
exports.restoreCache = core.getInput("restore-cache") === "true";
|
exports.restoreCache = core.getInput("restore-cache") === "true";
|
||||||
@@ -91072,6 +91074,17 @@ function getVersionFile() {
|
|||||||
}
|
}
|
||||||
return versionFileInput;
|
return versionFileInput;
|
||||||
}
|
}
|
||||||
|
function getVenvPath() {
|
||||||
|
const venvPathInput = core.getInput("venv-path");
|
||||||
|
if (venvPathInput !== "") {
|
||||||
|
if (!exports.activateEnvironment) {
|
||||||
|
core.warning("venv-path is only used when activate-environment is true");
|
||||||
|
}
|
||||||
|
const tildeExpanded = expandTilde(venvPathInput);
|
||||||
|
return normalizePath(resolveRelativePath(tildeExpanded));
|
||||||
|
}
|
||||||
|
return normalizePath(resolveRelativePath(".venv"));
|
||||||
|
}
|
||||||
function getEnableCache() {
|
function getEnableCache() {
|
||||||
const enableCacheInput = core.getInput("enable-cache");
|
const enableCacheInput = core.getInput("enable-cache");
|
||||||
if (enableCacheInput === "auto") {
|
if (enableCacheInput === "auto") {
|
||||||
@@ -91111,26 +91124,40 @@ function getCacheLocalPath() {
|
|||||||
const cacheLocalPathInput = core.getInput("cache-local-path");
|
const cacheLocalPathInput = core.getInput("cache-local-path");
|
||||||
if (cacheLocalPathInput !== "") {
|
if (cacheLocalPathInput !== "") {
|
||||||
const tildeExpanded = expandTilde(cacheLocalPathInput);
|
const tildeExpanded = expandTilde(cacheLocalPathInput);
|
||||||
return resolveRelativePath(tildeExpanded);
|
return {
|
||||||
|
path: resolveRelativePath(tildeExpanded),
|
||||||
|
source: CacheLocalSource.Input,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
const cacheDirFromConfig = getCacheDirFromConfig();
|
const cacheDirFromConfig = getCacheDirFromConfig();
|
||||||
if (cacheDirFromConfig !== undefined) {
|
if (cacheDirFromConfig !== undefined) {
|
||||||
return cacheDirFromConfig;
|
return { path: cacheDirFromConfig, source: CacheLocalSource.Config };
|
||||||
}
|
}
|
||||||
if (process.env.UV_CACHE_DIR !== undefined) {
|
if (process.env.UV_CACHE_DIR !== undefined) {
|
||||||
core.info(`UV_CACHE_DIR is already set to ${process.env.UV_CACHE_DIR}`);
|
core.info(`UV_CACHE_DIR is already set to ${process.env.UV_CACHE_DIR}`);
|
||||||
return process.env.UV_CACHE_DIR;
|
return { path: process.env.UV_CACHE_DIR, source: CacheLocalSource.Env };
|
||||||
}
|
}
|
||||||
if (process.env.RUNNER_ENVIRONMENT === "github-hosted") {
|
if (getEnableCache()) {
|
||||||
if (process.env.RUNNER_TEMP !== undefined) {
|
if (process.env.RUNNER_ENVIRONMENT === "github-hosted") {
|
||||||
return `${process.env.RUNNER_TEMP}${node_path_1.default.sep}setup-uv-cache`;
|
if (process.env.RUNNER_TEMP !== undefined) {
|
||||||
|
return {
|
||||||
|
path: `${process.env.RUNNER_TEMP}${node_path_1.default.sep}setup-uv-cache`,
|
||||||
|
source: CacheLocalSource.Default,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
throw Error("Could not determine UV_CACHE_DIR. Please make sure RUNNER_TEMP is set or provide the cache-local-path input");
|
||||||
}
|
}
|
||||||
throw Error("Could not determine UV_CACHE_DIR. Please make sure RUNNER_TEMP is set or provide the cache-local-path input");
|
if (process.platform === "win32") {
|
||||||
|
return {
|
||||||
|
path: `${process.env.APPDATA}${node_path_1.default.sep}uv${node_path_1.default.sep}cache`,
|
||||||
|
source: CacheLocalSource.Default,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
path: `${process.env.HOME}${node_path_1.default.sep}.cache${node_path_1.default.sep}uv`,
|
||||||
|
source: CacheLocalSource.Default,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (process.platform === "win32") {
|
|
||||||
return `${process.env.APPDATA}${node_path_1.default.sep}uv${node_path_1.default.sep}cache`;
|
|
||||||
}
|
|
||||||
return `${process.env.HOME}${node_path_1.default.sep}.cache${node_path_1.default.sep}uv`;
|
|
||||||
}
|
}
|
||||||
function getCacheDirFromConfig() {
|
function getCacheDirFromConfig() {
|
||||||
for (const filePath of [exports.versionFile, "uv.toml", "pyproject.toml"]) {
|
for (const filePath of [exports.versionFile, "uv.toml", "pyproject.toml"]) {
|
||||||
@@ -91152,7 +91179,7 @@ function getCacheDirFromConfig() {
|
|||||||
}
|
}
|
||||||
function getUvPythonDir() {
|
function getUvPythonDir() {
|
||||||
if (process.env.UV_PYTHON_INSTALL_DIR !== undefined) {
|
if (process.env.UV_PYTHON_INSTALL_DIR !== undefined) {
|
||||||
core.info(`UV_PYTHON_INSTALL_DIR is already set to ${process.env.UV_PYTHON_INSTALL_DIR}`);
|
core.info(`UV_PYTHON_INSTALL_DIR is already set to ${process.env.UV_PYTHON_INSTALL_DIR}`);
|
||||||
return process.env.UV_PYTHON_INSTALL_DIR;
|
return process.env.UV_PYTHON_INSTALL_DIR;
|
||||||
}
|
}
|
||||||
if (process.env.RUNNER_ENVIRONMENT !== "github-hosted") {
|
if (process.env.RUNNER_ENVIRONMENT !== "github-hosted") {
|
||||||
@@ -91186,6 +91213,16 @@ function expandTilde(input) {
|
|||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
function normalizePath(inputPath) {
|
||||||
|
const normalized = node_path_1.default.normalize(inputPath);
|
||||||
|
const root = node_path_1.default.parse(normalized).root;
|
||||||
|
// Remove any trailing path separators, except when the whole path is the root.
|
||||||
|
let trimmed = normalized;
|
||||||
|
while (trimmed.length > root.length && trimmed.endsWith(node_path_1.default.sep)) {
|
||||||
|
trimmed = trimmed.slice(0, -1);
|
||||||
|
}
|
||||||
|
return trimmed;
|
||||||
|
}
|
||||||
function resolveRelativePath(inputPath) {
|
function resolveRelativePath(inputPath) {
|
||||||
const hasNegation = inputPath.startsWith("!");
|
const hasNegation = inputPath.startsWith("!");
|
||||||
const pathWithoutNegation = hasNegation ? inputPath.substring(1) : inputPath;
|
const pathWithoutNegation = hasNegation ? inputPath.substring(1) : inputPath;
|
||||||
@@ -91252,9 +91289,15 @@ var __importStar = (this && this.__importStar) || (function () {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.getArch = getArch;
|
exports.getArch = getArch;
|
||||||
exports.getPlatform = getPlatform;
|
exports.getPlatform = getPlatform;
|
||||||
|
exports.getOSNameVersion = getOSNameVersion;
|
||||||
|
const node_fs_1 = __importDefault(__nccwpck_require__(3024));
|
||||||
|
const node_os_1 = __importDefault(__nccwpck_require__(8161));
|
||||||
const core = __importStar(__nccwpck_require__(7484));
|
const core = __importStar(__nccwpck_require__(7484));
|
||||||
const exec = __importStar(__nccwpck_require__(5236));
|
const exec = __importStar(__nccwpck_require__(5236));
|
||||||
function getArch() {
|
function getArch() {
|
||||||
@@ -91263,6 +91306,7 @@ function getArch() {
|
|||||||
arm64: "aarch64",
|
arm64: "aarch64",
|
||||||
ia32: "i686",
|
ia32: "i686",
|
||||||
ppc64: "powerpc64le",
|
ppc64: "powerpc64le",
|
||||||
|
riscv64: "riscv64gc",
|
||||||
s390x: "s390x",
|
s390x: "s390x",
|
||||||
x64: "x86_64",
|
x64: "x86_64",
|
||||||
};
|
};
|
||||||
@@ -91312,6 +91356,69 @@ async function isMuslOs() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Returns OS name and version for cache key differentiation.
|
||||||
|
* Examples: "ubuntu-22.04", "macos-14", "windows-2022"
|
||||||
|
* Throws if OS detection fails.
|
||||||
|
*/
|
||||||
|
function getOSNameVersion() {
|
||||||
|
const platform = process.platform;
|
||||||
|
if (platform === "linux") {
|
||||||
|
return getLinuxOSNameVersion();
|
||||||
|
}
|
||||||
|
if (platform === "darwin") {
|
||||||
|
return getMacOSNameVersion();
|
||||||
|
}
|
||||||
|
if (platform === "win32") {
|
||||||
|
return getWindowsNameVersion();
|
||||||
|
}
|
||||||
|
throw new Error(`Unsupported platform: ${platform}`);
|
||||||
|
}
|
||||||
|
function getLinuxOSNameVersion() {
|
||||||
|
const files = ["/etc/os-release", "/usr/lib/os-release"];
|
||||||
|
for (const file of files) {
|
||||||
|
try {
|
||||||
|
const content = node_fs_1.default.readFileSync(file, "utf8");
|
||||||
|
const id = parseOsReleaseValue(content, "ID");
|
||||||
|
const versionId = parseOsReleaseValue(content, "VERSION_ID");
|
||||||
|
// Fallback for rolling releases (debian:unstable/testing, arch, etc.)
|
||||||
|
// that don't have VERSION_ID but have VERSION_CODENAME
|
||||||
|
const versionCodename = parseOsReleaseValue(content, "VERSION_CODENAME");
|
||||||
|
if (id && versionId) {
|
||||||
|
return `${id}-${versionId}`;
|
||||||
|
}
|
||||||
|
if (id && versionCodename) {
|
||||||
|
return `${id}-${versionCodename}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
// Try next file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error("Failed to determine Linux distribution. " +
|
||||||
|
"Could not read /etc/os-release or /usr/lib/os-release");
|
||||||
|
}
|
||||||
|
function parseOsReleaseValue(content, key) {
|
||||||
|
const regex = new RegExp(`^${key}=["']?([^"'\\n]*)["']?$`, "m");
|
||||||
|
const match = content.match(regex);
|
||||||
|
return match?.[1];
|
||||||
|
}
|
||||||
|
function getMacOSNameVersion() {
|
||||||
|
const darwinVersion = Number.parseInt(node_os_1.default.release().split(".")[0], 10);
|
||||||
|
if (Number.isNaN(darwinVersion)) {
|
||||||
|
throw new Error(`Failed to parse macOS version from: ${node_os_1.default.release()}`);
|
||||||
|
}
|
||||||
|
const macosVersion = darwinVersion - 9;
|
||||||
|
return `macos-${macosVersion}`;
|
||||||
|
}
|
||||||
|
function getWindowsNameVersion() {
|
||||||
|
const version = node_os_1.default.version();
|
||||||
|
const match = version.match(/Windows(?: Server)? (\d+)/);
|
||||||
|
if (!match) {
|
||||||
|
throw new Error(`Failed to parse Windows version from: ${version}`);
|
||||||
|
}
|
||||||
|
return `windows-${match[1]}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
@@ -91452,6 +91559,14 @@ module.exports = require("node:fs");
|
|||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ 8161:
|
||||||
|
/***/ ((module) => {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
module.exports = require("node:os");
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
/***/ 6760:
|
/***/ 6760:
|
||||||
/***/ ((module) => {
|
/***/ ((module) => {
|
||||||
|
|
||||||
@@ -93370,7 +93485,7 @@ function getStringEnd(str, seek) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// dist/date.js
|
// dist/date.js
|
||||||
var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}:\d{2}(?:\.\d+)?)?(Z|[-+]\d{2}:\d{2})?$/i;
|
var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
|
||||||
var TomlDate = class _TomlDate extends Date {
|
var TomlDate = class _TomlDate extends Date {
|
||||||
#hasDate = false;
|
#hasDate = false;
|
||||||
#hasTime = false;
|
#hasTime = false;
|
||||||
@@ -93465,13 +93580,14 @@ var TomlDate = class _TomlDate extends Date {
|
|||||||
var INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/;
|
var INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/;
|
||||||
var FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/;
|
var FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/;
|
||||||
var LEADING_ZERO = /^[+-]?0[0-9_]/;
|
var LEADING_ZERO = /^[+-]?0[0-9_]/;
|
||||||
var ESCAPE_REGEX = /^[0-9a-f]{4,8}$/i;
|
var ESCAPE_REGEX = /^[0-9a-f]{2,8}$/i;
|
||||||
var ESC_MAP = {
|
var ESC_MAP = {
|
||||||
b: "\b",
|
b: "\b",
|
||||||
t: " ",
|
t: " ",
|
||||||
n: "\n",
|
n: "\n",
|
||||||
f: "\f",
|
f: "\f",
|
||||||
r: "\r",
|
r: "\r",
|
||||||
|
e: "\x1B",
|
||||||
'"': '"',
|
'"': '"',
|
||||||
"\\": "\\"
|
"\\": "\\"
|
||||||
};
|
};
|
||||||
@@ -93506,8 +93622,8 @@ function parseString(str, ptr = 0, endPtr = str.length) {
|
|||||||
}
|
}
|
||||||
if (isEscape) {
|
if (isEscape) {
|
||||||
isEscape = false;
|
isEscape = false;
|
||||||
if (c === "u" || c === "U") {
|
if (c === "x" || c === "u" || c === "U") {
|
||||||
let code = str.slice(ptr, ptr += c === "u" ? 4 : 8);
|
let code = str.slice(ptr, ptr += c === "x" ? 2 : c === "u" ? 4 : 8);
|
||||||
if (!ESCAPE_REGEX.test(code)) {
|
if (!ESCAPE_REGEX.test(code)) {
|
||||||
throw new TomlError("invalid unicode escape", {
|
throw new TomlError("invalid unicode escape", {
|
||||||
toml: str,
|
toml: str,
|
||||||
@@ -93600,24 +93716,14 @@ function parseValue(value, toml, ptr, integersAsBigInt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// dist/extract.js
|
// dist/extract.js
|
||||||
function sliceAndTrimEndOf(str, startPtr, endPtr, allowNewLines) {
|
function sliceAndTrimEndOf(str, startPtr, endPtr) {
|
||||||
let value = str.slice(startPtr, endPtr);
|
let value = str.slice(startPtr, endPtr);
|
||||||
let commentIdx = value.indexOf("#");
|
let commentIdx = value.indexOf("#");
|
||||||
if (commentIdx > -1) {
|
if (commentIdx > -1) {
|
||||||
skipComment(str, commentIdx);
|
skipComment(str, commentIdx);
|
||||||
value = value.slice(0, commentIdx);
|
value = value.slice(0, commentIdx);
|
||||||
}
|
}
|
||||||
let trimmed = value.trimEnd();
|
return [value.trimEnd(), commentIdx];
|
||||||
if (!allowNewLines) {
|
|
||||||
let newlineIdx = value.indexOf("\n", trimmed.length);
|
|
||||||
if (newlineIdx > -1) {
|
|
||||||
throw new TomlError("newlines are not allowed in inline tables", {
|
|
||||||
toml: str,
|
|
||||||
ptr: startPtr + newlineIdx
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [trimmed, commentIdx];
|
|
||||||
}
|
}
|
||||||
function extractValue(str, ptr, end, depth, integersAsBigInt) {
|
function extractValue(str, ptr, end, depth, integersAsBigInt) {
|
||||||
if (depth === 0) {
|
if (depth === 0) {
|
||||||
@@ -93629,24 +93735,25 @@ function extractValue(str, ptr, end, depth, integersAsBigInt) {
|
|||||||
let c = str[ptr];
|
let c = str[ptr];
|
||||||
if (c === "[" || c === "{") {
|
if (c === "[" || c === "{") {
|
||||||
let [value, endPtr2] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt);
|
let [value, endPtr2] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt);
|
||||||
let newPtr = end ? skipUntil(str, endPtr2, ",", end) : endPtr2;
|
if (end) {
|
||||||
if (endPtr2 - newPtr && end === "}") {
|
endPtr2 = skipVoid(str, endPtr2);
|
||||||
let nextNewLine = indexOfNewline(str, endPtr2, newPtr);
|
if (str[endPtr2] === ",")
|
||||||
if (nextNewLine > -1) {
|
endPtr2++;
|
||||||
throw new TomlError("newlines are not allowed in inline tables", {
|
else if (str[endPtr2] !== end) {
|
||||||
|
throw new TomlError("expected comma or end of structure", {
|
||||||
toml: str,
|
toml: str,
|
||||||
ptr: nextNewLine
|
ptr: endPtr2
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [value, newPtr];
|
return [value, endPtr2];
|
||||||
}
|
}
|
||||||
let endPtr;
|
let endPtr;
|
||||||
if (c === '"' || c === "'") {
|
if (c === '"' || c === "'") {
|
||||||
endPtr = getStringEnd(str, ptr);
|
endPtr = getStringEnd(str, ptr);
|
||||||
let parsed = parseString(str, ptr, endPtr);
|
let parsed = parseString(str, ptr, endPtr);
|
||||||
if (end) {
|
if (end) {
|
||||||
endPtr = skipVoid(str, endPtr, end !== "]");
|
endPtr = skipVoid(str, endPtr);
|
||||||
if (str[endPtr] && str[endPtr] !== "," && str[endPtr] !== end && str[endPtr] !== "\n" && str[endPtr] !== "\r") {
|
if (str[endPtr] && str[endPtr] !== "," && str[endPtr] !== end && str[endPtr] !== "\n" && str[endPtr] !== "\r") {
|
||||||
throw new TomlError("unexpected character encountered", {
|
throw new TomlError("unexpected character encountered", {
|
||||||
toml: str,
|
toml: str,
|
||||||
@@ -93658,7 +93765,7 @@ function extractValue(str, ptr, end, depth, integersAsBigInt) {
|
|||||||
return [parsed, endPtr];
|
return [parsed, endPtr];
|
||||||
}
|
}
|
||||||
endPtr = skipUntil(str, ptr, ",", end);
|
endPtr = skipUntil(str, ptr, ",", end);
|
||||||
let slice = sliceAndTrimEndOf(str, ptr, endPtr - +(str[endPtr - 1] === ","), end === "]");
|
let slice = sliceAndTrimEndOf(str, ptr, endPtr - +(str[endPtr - 1] === ","));
|
||||||
if (!slice[0]) {
|
if (!slice[0]) {
|
||||||
throw new TomlError("incomplete key-value declaration: no value specified", {
|
throw new TomlError("incomplete key-value declaration: no value specified", {
|
||||||
toml: str,
|
toml: str,
|
||||||
@@ -93748,17 +93855,16 @@ function parseInlineTable(str, ptr, depth, integersAsBigInt) {
|
|||||||
let res = {};
|
let res = {};
|
||||||
let seen = /* @__PURE__ */ new Set();
|
let seen = /* @__PURE__ */ new Set();
|
||||||
let c;
|
let c;
|
||||||
let comma = 0;
|
|
||||||
ptr++;
|
ptr++;
|
||||||
while ((c = str[ptr++]) !== "}" && c) {
|
while ((c = str[ptr++]) !== "}" && c) {
|
||||||
let err = { toml: str, ptr: ptr - 1 };
|
if (c === ",") {
|
||||||
if (c === "\n") {
|
throw new TomlError("expected value, found comma", {
|
||||||
throw new TomlError("newlines are not allowed in inline tables", err);
|
toml: str,
|
||||||
} else if (c === "#") {
|
ptr: ptr - 1
|
||||||
throw new TomlError("inline tables cannot contain comments", err);
|
});
|
||||||
} else if (c === ",") {
|
} else if (c === "#")
|
||||||
throw new TomlError("expected key-value, found comma", err);
|
ptr = skipComment(str, ptr);
|
||||||
} else if (c !== " " && c !== " ") {
|
else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
|
||||||
let k;
|
let k;
|
||||||
let t = res;
|
let t = res;
|
||||||
let hasOwn = false;
|
let hasOwn = false;
|
||||||
@@ -93787,15 +93893,8 @@ function parseInlineTable(str, ptr, depth, integersAsBigInt) {
|
|||||||
seen.add(value);
|
seen.add(value);
|
||||||
t[k] = value;
|
t[k] = value;
|
||||||
ptr = valueEndPtr;
|
ptr = valueEndPtr;
|
||||||
comma = str[ptr - 1] === "," ? ptr - 1 : 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (comma) {
|
|
||||||
throw new TomlError("trailing commas are not allowed in inline tables", {
|
|
||||||
toml: str,
|
|
||||||
ptr: comma
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (!c) {
|
if (!c) {
|
||||||
throw new TomlError("unfinished table encountered", {
|
throw new TomlError("unfinished table encountered", {
|
||||||
toml: str,
|
toml: str,
|
||||||
@@ -94047,14 +94146,13 @@ function stringifyArrayTable(array, key, depth, numberAsFloat) {
|
|||||||
}
|
}
|
||||||
let res = "";
|
let res = "";
|
||||||
for (let i = 0; i < array.length; i++) {
|
for (let i = 0; i < array.length; i++) {
|
||||||
res += `[[${key}]]
|
res += `${res && "\n"}[[${key}]]
|
||||||
`;
|
`;
|
||||||
res += stringifyTable(array[i], key, depth, numberAsFloat);
|
res += stringifyTable(0, array[i], key, depth, numberAsFloat);
|
||||||
res += "\n\n";
|
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
function stringifyTable(obj, prefix, depth, numberAsFloat) {
|
function stringifyTable(tableKey, obj, prefix, depth, numberAsFloat) {
|
||||||
if (depth === 0) {
|
if (depth === 0) {
|
||||||
throw new Error("Could not stringify the object: maximum object depth exceeded");
|
throw new Error("Could not stringify the object: maximum object depth exceeded");
|
||||||
}
|
}
|
||||||
@@ -94070,13 +94168,10 @@ function stringifyTable(obj, prefix, depth, numberAsFloat) {
|
|||||||
}
|
}
|
||||||
let key = BARE_KEY.test(k) ? k : formatString(k);
|
let key = BARE_KEY.test(k) ? k : formatString(k);
|
||||||
if (type === "array" && isArrayOfTables(obj[k])) {
|
if (type === "array" && isArrayOfTables(obj[k])) {
|
||||||
tables += stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat);
|
tables += (tables && "\n") + stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat);
|
||||||
} else if (type === "object") {
|
} else if (type === "object") {
|
||||||
let tblKey = prefix ? `${prefix}.${key}` : key;
|
let tblKey = prefix ? `${prefix}.${key}` : key;
|
||||||
tables += `[${tblKey}]
|
tables += (tables && "\n") + stringifyTable(tblKey, obj[k], tblKey, depth - 1, numberAsFloat);
|
||||||
`;
|
|
||||||
tables += stringifyTable(obj[k], tblKey, depth - 1, numberAsFloat);
|
|
||||||
tables += "\n\n";
|
|
||||||
} else {
|
} else {
|
||||||
preamble += key;
|
preamble += key;
|
||||||
preamble += " = ";
|
preamble += " = ";
|
||||||
@@ -94085,14 +94180,20 @@ function stringifyTable(obj, prefix, depth, numberAsFloat) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return `${preamble}
|
if (tableKey && (preamble || !tables))
|
||||||
${tables}`.trim();
|
preamble = preamble ? `[${tableKey}]
|
||||||
|
${preamble}` : `[${tableKey}]`;
|
||||||
|
return preamble && tables ? `${preamble}
|
||||||
|
${tables}` : preamble || tables;
|
||||||
}
|
}
|
||||||
function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
|
function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
|
||||||
if (extendedTypeOf(obj) !== "object") {
|
if (extendedTypeOf(obj) !== "object") {
|
||||||
throw new TypeError("stringify can only be called with an object");
|
throw new TypeError("stringify can only be called with an object");
|
||||||
}
|
}
|
||||||
return stringifyTable(obj, "", maxDepth, numbersAsFloat);
|
let str = stringifyTable(0, obj, "", maxDepth, numbersAsFloat);
|
||||||
|
if (str[str.length - 1] !== "\n")
|
||||||
|
return str + "\n";
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
// dist/index.js
|
// dist/index.js
|
||||||
|
|||||||
5620
dist/setup/index.js
generated
vendored
5620
dist/setup/index.js
generated
vendored
File diff suppressed because it is too large
Load Diff
6121
dist/update-known-versions/index.js → dist/update-known-checksums/index.js
generated
vendored
6121
dist/update-known-versions/index.js → dist/update-known-checksums/index.js
generated
vendored
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,34 @@
|
|||||||
|
|
||||||
This document covers all caching-related configuration options for setup-uv.
|
This document covers all caching-related configuration options for setup-uv.
|
||||||
|
|
||||||
|
## Cache key
|
||||||
|
|
||||||
|
The cache key is automatically generated based on:
|
||||||
|
|
||||||
|
- **Architecture**: CPU architecture (e.g., `x86_64`, `aarch64`)
|
||||||
|
- **Platform**: OS platform type (e.g., `unknown-linux-gnu`, `unknown-linux-musl`, `apple-darwin`,
|
||||||
|
`pc-windows-msvc`)
|
||||||
|
- **OS version**: OS name and version (e.g., `ubuntu-22.04`, `macos-14`, `windows-2022`)
|
||||||
|
- **Python version**: The Python version in use
|
||||||
|
- **Cache options**: Whether pruning and Python caching are enabled
|
||||||
|
- **Dependency hash**: Hash of files matching `cache-dependency-glob`
|
||||||
|
- **Suffix**: Optional `cache-suffix` if provided
|
||||||
|
|
||||||
|
Including the OS version ensures that caches are not shared between different OS versions,
|
||||||
|
preventing binary incompatibility issues when runner images change.
|
||||||
|
|
||||||
|
The computed cache key is available as the `cache-key` output:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Setup uv
|
||||||
|
id: setup-uv
|
||||||
|
uses: astral-sh/setup-uv@v7
|
||||||
|
with:
|
||||||
|
enable-cache: true
|
||||||
|
- name: Print cache key
|
||||||
|
run: echo "Cache key: ${{ steps.setup-uv.outputs.cache-key }}"
|
||||||
|
```
|
||||||
|
|
||||||
## Enable caching
|
## Enable caching
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
@@ -134,6 +162,10 @@ It defaults to `setup-uv-cache` in the `TMP` dir, `D:\a\_temp\setup-uv-cache` on
|
|||||||
> If you configured [cache-dir](https://docs.astral.sh/uv/reference/settings/#cache-dir) in your
|
> If you configured [cache-dir](https://docs.astral.sh/uv/reference/settings/#cache-dir) in your
|
||||||
> config file then it is also respected and this action will not set `UV_CACHE_DIR`.
|
> config file then it is also respected and this action will not set `UV_CACHE_DIR`.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> If caching is disabled, you can still use `cache-local-path` so this action sets `UV_CACHE_DIR`
|
||||||
|
> to your desired path.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Define a custom uv cache path
|
- name: Define a custom uv cache path
|
||||||
uses: astral-sh/setup-uv@v7
|
uses: astral-sh/setup-uv@v7
|
||||||
@@ -167,6 +199,10 @@ By default, the Python install dir (`uv python dir` / `UV_PYTHON_INSTALL_DIR`) i
|
|||||||
for the same reason that the dependency cache is pruned.
|
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`.
|
If you want to cache Python installs along with your dependencies, set the `cache-python` input to `true`.
|
||||||
|
|
||||||
|
Note that this only caches Python versions that uv actually installs into `UV_PYTHON_INSTALL_DIR`
|
||||||
|
(i.e. managed Python installs). If uv uses a system Python, there may be nothing to cache.
|
||||||
|
To force managed Python installs, set `UV_PYTHON_PREFERENCE=only-managed`.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Cache Python installs
|
- name: Cache Python installs
|
||||||
uses: astral-sh/setup-uv@v7
|
uses: astral-sh/setup-uv@v7
|
||||||
|
|||||||
@@ -18,12 +18,29 @@ are automatically verified by this action. The sha256 hashes can be found on the
|
|||||||
|
|
||||||
## Manifest file
|
## Manifest file
|
||||||
|
|
||||||
The `manifest-file` input allows you to specify a JSON manifest that lists available uv versions,
|
By default, setup-uv reads version metadata from
|
||||||
architectures, and their download URLs. By default, this action uses the manifest file contained
|
[`astral-sh/versions`](https://github.com/astral-sh/versions) (NDJSON format).
|
||||||
in this repository, which is automatically updated with each release of uv.
|
|
||||||
|
|
||||||
The manifest file contains an array of objects, each describing a version,
|
The `manifest-file` input lets you override that source with your own URL, for example to test
|
||||||
architecture, platform, and the corresponding download URL. For example:
|
custom uv builds or alternate download locations.
|
||||||
|
|
||||||
|
### Format
|
||||||
|
|
||||||
|
The manifest file must be in NDJSON format, where each line is a JSON object representing a version and its artifacts. For example:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"version":"0.10.7","artifacts":[{"platform":"x86_64-unknown-linux-gnu","variant":"default","url":"https://example.com/uv-x86_64-unknown-linux-gnu.tar.gz","archive_format":"tar.gz","sha256":"..."}]}
|
||||||
|
{"version":"0.10.6","artifacts":[{"platform":"x86_64-unknown-linux-gnu","variant":"default","url":"https://example.com/uv-x86_64-unknown-linux-gnu.tar.gz","archive_format":"tar.gz","sha256":"..."}]}
|
||||||
|
```
|
||||||
|
|
||||||
|
setup-uv currently only supports `default` as the `variant`.
|
||||||
|
|
||||||
|
The `archive_format` field is currently ignored.
|
||||||
|
|
||||||
|
### Legacy format: JSON array (deprecated)
|
||||||
|
|
||||||
|
The previous JSON array format is still supported for compatibility, but deprecated and will be
|
||||||
|
removed in a future major release.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
[
|
[
|
||||||
@@ -33,26 +50,20 @@ architecture, platform, and the corresponding download URL. For example:
|
|||||||
"arch": "aarch64",
|
"arch": "aarch64",
|
||||||
"platform": "apple-darwin",
|
"platform": "apple-darwin",
|
||||||
"downloadUrl": "https://github.com/astral-sh/uv/releases/download/0.7.13/uv-aarch64-apple-darwin.tar.gz"
|
"downloadUrl": "https://github.com/astral-sh/uv/releases/download/0.7.13/uv-aarch64-apple-darwin.tar.gz"
|
||||||
},
|
}
|
||||||
...
|
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
You can supply a custom manifest file URL to define additional versions,
|
|
||||||
architectures, or different download URLs.
|
|
||||||
This is useful if you maintain your own uv builds or want to override the default sources.
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Use a custom manifest file
|
- name: Use a custom manifest file
|
||||||
uses: astral-sh/setup-uv@v7
|
uses: astral-sh/setup-uv@v7
|
||||||
with:
|
with:
|
||||||
manifest-file: "https://example.com/my-custom-manifest.json"
|
manifest-file: "https://example.com/my-custom-manifest.ndjson"
|
||||||
```
|
```
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> When you use a custom manifest file and do not set the `version` input, its default value is `latest`.
|
> When you use a custom manifest file and do not set the `version` input, setup-uv installs the
|
||||||
> This means the action will install the latest version available in the custom manifest file.
|
> latest version from that custom manifest.
|
||||||
> This is different from the default behavior of installing the latest version from the official uv releases.
|
|
||||||
|
|
||||||
## Add problem matchers
|
## Add problem matchers
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,17 @@ This allows directly using it in later steps:
|
|||||||
- run: uv pip install pip
|
- run: uv pip install pip
|
||||||
```
|
```
|
||||||
|
|
||||||
|
By default, the venv is created at `.venv` inside the `working-directory`.
|
||||||
|
|
||||||
|
You can customize the venv location with `venv-path`, for example to place it in the runner temp directory:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: astral-sh/setup-uv@v7
|
||||||
|
with:
|
||||||
|
activate-environment: true
|
||||||
|
venv-path: ${{ runner.temp }}/custom-venv
|
||||||
|
```
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
>
|
>
|
||||||
> Activating the environment adds your dependencies to the `PATH`, which could break some workflows.
|
> Activating the environment adds your dependencies to the `PATH`, which could break some workflows.
|
||||||
@@ -27,9 +38,12 @@ This allows directly using it in later steps:
|
|||||||
|
|
||||||
## GitHub authentication token
|
## GitHub authentication token
|
||||||
|
|
||||||
This action uses the GitHub API to fetch the uv release artifacts. To avoid hitting the GitHub API
|
By default, this action resolves available uv versions from
|
||||||
rate limit too quickly, an authentication token can be provided via the `github-token` input. By
|
[`astral-sh/versions`](https://github.com/astral-sh/versions), then downloads uv artifacts from
|
||||||
default, the `GITHUB_TOKEN` secret is used, which is automatically provided by GitHub Actions.
|
GitHub Releases.
|
||||||
|
|
||||||
|
You can provide a token via `github-token` to authenticate those downloads. By default, the
|
||||||
|
`GITHUB_TOKEN` secret is used, which is automatically provided by GitHub Actions.
|
||||||
|
|
||||||
If the default
|
If the default
|
||||||
[permissions for the GitHub token](https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication#permissions-for-the-github_token)
|
[permissions for the GitHub token](https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication#permissions-for-the-github_token)
|
||||||
|
|||||||
523
package-lock.json
generated
523
package-lock.json
generated
@@ -15,17 +15,14 @@
|
|||||||
"@actions/glob": "^0.5.0",
|
"@actions/glob": "^0.5.0",
|
||||||
"@actions/io": "^1.1.3",
|
"@actions/io": "^1.1.3",
|
||||||
"@actions/tool-cache": "^2.0.2",
|
"@actions/tool-cache": "^2.0.2",
|
||||||
"@octokit/core": "^7.0.5",
|
|
||||||
"@octokit/plugin-paginate-rest": "^13.2.1",
|
|
||||||
"@octokit/plugin-rest-endpoint-methods": "^16.1.1",
|
|
||||||
"@renovatebot/pep440": "^4.2.1",
|
"@renovatebot/pep440": "^4.2.1",
|
||||||
"smol-toml": "^1.4.2",
|
"smol-toml": "^1.6.0",
|
||||||
"undici": "5.28.5"
|
"undici": "7.22.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "2.3.0",
|
"@biomejs/biome": "2.3.8",
|
||||||
"@types/js-yaml": "^4.0.9",
|
"@types/js-yaml": "^4.0.9",
|
||||||
"@types/node": "^24.9.1",
|
"@types/node": "^24.10.1",
|
||||||
"@types/semver": "^7.7.1",
|
"@types/semver": "^7.7.1",
|
||||||
"@vercel/ncc": "^0.38.4",
|
"@vercel/ncc": "^0.38.4",
|
||||||
"jest": "^30.2.0",
|
"jest": "^30.2.0",
|
||||||
@@ -96,6 +93,17 @@
|
|||||||
"undici": "^5.25.4"
|
"undici": "^5.25.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@actions/http-client/node_modules/undici": {
|
||||||
|
"version": "5.29.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz",
|
||||||
|
"integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@fastify/busboy": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@actions/io": {
|
"node_modules/@actions/io": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
|
||||||
@@ -412,7 +420,6 @@
|
|||||||
"integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
|
"integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ampproject/remapping": "^2.2.0",
|
"@ampproject/remapping": "^2.2.0",
|
||||||
"@babel/code-frame": "^7.27.1",
|
"@babel/code-frame": "^7.27.1",
|
||||||
@@ -890,9 +897,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@biomejs/biome": {
|
"node_modules/@biomejs/biome": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.8.tgz",
|
||||||
"integrity": "sha512-shdUY5H3S3tJVUWoVWo5ua+GdPW5lRHf+b0IwZ4OC1o2zOKQECZ6l2KbU6t89FNhtd3Qx5eg5N7/UsQWGQbAFw==",
|
"integrity": "sha512-Qjsgoe6FEBxWAUzwFGFrB+1+M8y/y5kwmg5CHac+GSVOdmOIqsAiXM5QMVGZJ1eCUCLlPZtq4aFAQ0eawEUuUA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -906,20 +913,20 @@
|
|||||||
"url": "https://opencollective.com/biome"
|
"url": "https://opencollective.com/biome"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@biomejs/cli-darwin-arm64": "2.3.0",
|
"@biomejs/cli-darwin-arm64": "2.3.8",
|
||||||
"@biomejs/cli-darwin-x64": "2.3.0",
|
"@biomejs/cli-darwin-x64": "2.3.8",
|
||||||
"@biomejs/cli-linux-arm64": "2.3.0",
|
"@biomejs/cli-linux-arm64": "2.3.8",
|
||||||
"@biomejs/cli-linux-arm64-musl": "2.3.0",
|
"@biomejs/cli-linux-arm64-musl": "2.3.8",
|
||||||
"@biomejs/cli-linux-x64": "2.3.0",
|
"@biomejs/cli-linux-x64": "2.3.8",
|
||||||
"@biomejs/cli-linux-x64-musl": "2.3.0",
|
"@biomejs/cli-linux-x64-musl": "2.3.8",
|
||||||
"@biomejs/cli-win32-arm64": "2.3.0",
|
"@biomejs/cli-win32-arm64": "2.3.8",
|
||||||
"@biomejs/cli-win32-x64": "2.3.0"
|
"@biomejs/cli-win32-x64": "2.3.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@biomejs/cli-darwin-arm64": {
|
"node_modules/@biomejs/cli-darwin-arm64": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.8.tgz",
|
||||||
"integrity": "sha512-3cJVT0Z5pbTkoBmbjmDZTDFYxIkRcrs9sYVJbIBHU8E6qQxgXAaBfSVjjCreG56rfDuQBr43GzwzmaHPcu4vlw==",
|
"integrity": "sha512-HM4Zg9CGQ3txTPflxD19n8MFPrmUAjaC7PQdLkugeeC0cQ+PiVrd7i09gaBS/11QKsTDBJhVg85CEIK9f50Qww==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -934,9 +941,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@biomejs/cli-darwin-x64": {
|
"node_modules/@biomejs/cli-darwin-x64": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.3.8.tgz",
|
||||||
"integrity": "sha512-6LIkhglh3UGjuDqJXsK42qCA0XkD1Ke4K/raFOii7QQPbM8Pia7Qj2Hji4XuF2/R78hRmEx7uKJH3t/Y9UahtQ==",
|
"integrity": "sha512-lUDQ03D7y/qEao7RgdjWVGCu+BLYadhKTm40HkpJIi6kn8LSv5PAwRlew/DmwP4YZ9ke9XXoTIQDO1vAnbRZlA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -951,9 +958,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@biomejs/cli-linux-arm64": {
|
"node_modules/@biomejs/cli-linux-arm64": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.3.8.tgz",
|
||||||
"integrity": "sha512-uhAsbXySX7xsXahegDg5h3CDgfMcRsJvWLFPG0pjkylgBb9lErbK2C0UINW52zhwg0cPISB09lxHPxCau4e2xA==",
|
"integrity": "sha512-Uo1OJnIkJgSgF+USx970fsM/drtPcQ39I+JO+Fjsaa9ZdCN1oysQmy6oAGbyESlouz+rzEckLTF6DS7cWse95g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -968,9 +975,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@biomejs/cli-linux-arm64-musl": {
|
"node_modules/@biomejs/cli-linux-arm64-musl": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.3.8.tgz",
|
||||||
"integrity": "sha512-nDksoFdwZ2YrE7NiYDhtMhL2UgFn8Kb7Y0bYvnTAakHnqEdb4lKindtBc1f+xg2Snz0JQhJUYO7r9CDBosRU5w==",
|
"integrity": "sha512-PShR4mM0sjksUMyxbyPNMxoKFPVF48fU8Qe8Sfx6w6F42verbwRLbz+QiKNiDPRJwUoMG1nPM50OBL3aOnTevA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -985,9 +992,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@biomejs/cli-linux-x64": {
|
"node_modules/@biomejs/cli-linux-x64": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.3.8.tgz",
|
||||||
"integrity": "sha512-uxa8reA2s1VgoH8MhbGlCmMOt3JuSE1vJBifkh1ulaPiuk0SPx8cCdpnm9NWnTe2x/LfWInWx4sZ7muaXTPGGw==",
|
"integrity": "sha512-QDPMD5bQz6qOVb3kiBui0zKZXASLo0NIQ9JVJio5RveBEFgDgsvJFUvZIbMbUZT3T00M/1wdzwWXk4GIh0KaAw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1002,9 +1009,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@biomejs/cli-linux-x64-musl": {
|
"node_modules/@biomejs/cli-linux-x64-musl": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.3.8.tgz",
|
||||||
"integrity": "sha512-+i9UcJwl99uAhtRQDz9jUAh+Xkb097eekxs/D9j4deWDg5/yB/jPWzISe1nBHvlzTXsdUSj0VvB4Go2DSpKIMw==",
|
"integrity": "sha512-YGLkqU91r1276uwSjiUD/xaVikdxgV1QpsicT0bIA1TaieM6E5ibMZeSyjQ/izBn4tKQthUSsVZacmoJfa3pDA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1019,9 +1026,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@biomejs/cli-win32-arm64": {
|
"node_modules/@biomejs/cli-win32-arm64": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.3.8.tgz",
|
||||||
"integrity": "sha512-ynjmsJLIKrAjC3CCnKMMhzcnNy8dbQWjKfSU5YA0mIruTxBNMbkAJp+Pr2iV7/hFou+66ZSD/WV8hmLEmhUaXA==",
|
"integrity": "sha512-H4IoCHvL1fXKDrTALeTKMiE7GGWFAraDwBYFquE/L/5r1927Te0mYIGseXi4F+lrrwhSWbSGt5qPFswNoBaCxg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1036,9 +1043,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@biomejs/cli-win32-x64": {
|
"node_modules/@biomejs/cli-win32-x64": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.3.8.tgz",
|
||||||
"integrity": "sha512-zOCYmCRVkWXc9v8P7OLbLlGGMxQTKMvi+5IC4v7O8DkjLCOHRzRVK/Lno2pGZNo0lzKM60pcQOhH8HVkXMQdFg==",
|
"integrity": "sha512-RguzimPoZWtBapfKhKjcWXBVI91tiSprqdBYu7tWhgN8pKRZhw24rFeNZTNf6UiBfjCYCi9eFQs/JzJZIhuK4w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1164,9 +1171,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
|
"node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
|
||||||
"version": "3.14.1",
|
"version": "3.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
|
||||||
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1590,134 +1597,6 @@
|
|||||||
"@tybys/wasm-util": "^0.10.0"
|
"@tybys/wasm-util": "^0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@octokit/auth-token": {
|
|
||||||
"version": "6.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz",
|
|
||||||
"integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 20"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/core": {
|
|
||||||
"version": "7.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.5.tgz",
|
|
||||||
"integrity": "sha512-t54CUOsFMappY1Jbzb7fetWeO0n6K0k/4+/ZpkS+3Joz8I4VcvY9OiEBFRYISqaI2fq5sCiPtAjRDOzVYG8m+Q==",
|
|
||||||
"license": "MIT",
|
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/auth-token": "^6.0.0",
|
|
||||||
"@octokit/graphql": "^9.0.2",
|
|
||||||
"@octokit/request": "^10.0.4",
|
|
||||||
"@octokit/request-error": "^7.0.1",
|
|
||||||
"@octokit/types": "^15.0.0",
|
|
||||||
"before-after-hook": "^4.0.0",
|
|
||||||
"universal-user-agent": "^7.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 20"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/endpoint": {
|
|
||||||
"version": "11.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.1.tgz",
|
|
||||||
"integrity": "sha512-7P1dRAZxuWAOPI7kXfio88trNi/MegQ0IJD3vfgC3b+LZo1Qe6gRJc2v0mz2USWWJOKrB2h5spXCzGbw+fAdqA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/types": "^15.0.0",
|
|
||||||
"universal-user-agent": "^7.0.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 20"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/graphql": {
|
|
||||||
"version": "9.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.2.tgz",
|
|
||||||
"integrity": "sha512-iz6KzZ7u95Fzy9Nt2L8cG88lGRMr/qy1Q36ih/XVzMIlPDMYwaNLE/ENhqmIzgPrlNWiYJkwmveEetvxAgFBJw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/request": "^10.0.4",
|
|
||||||
"@octokit/types": "^15.0.0",
|
|
||||||
"universal-user-agent": "^7.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 20"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/openapi-types": {
|
|
||||||
"version": "26.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-26.0.0.tgz",
|
|
||||||
"integrity": "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/plugin-paginate-rest": {
|
|
||||||
"version": "13.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-13.2.1.tgz",
|
|
||||||
"integrity": "sha512-Tj4PkZyIL6eBMYcG/76QGsedF0+dWVeLhYprTmuFVVxzDW7PQh23tM0TP0z+1MvSkxB29YFZwnUX+cXfTiSdyw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/types": "^15.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 20"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@octokit/core": ">=6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/plugin-rest-endpoint-methods": {
|
|
||||||
"version": "16.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-16.1.1.tgz",
|
|
||||||
"integrity": "sha512-VztDkhM0ketQYSh5Im3IcKWFZl7VIrrsCaHbDINkdYeiiAsJzjhS2xRFCSJgfN6VOcsoW4laMtsmf3HcNqIimg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/types": "^15.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 20"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@octokit/core": ">=6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/request": {
|
|
||||||
"version": "10.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.5.tgz",
|
|
||||||
"integrity": "sha512-TXnouHIYLtgDhKo+N6mXATnDBkV05VwbR0TtMWpgTHIoQdRQfCSzmy/LGqR1AbRMbijq/EckC/E3/ZNcU92NaQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/endpoint": "^11.0.1",
|
|
||||||
"@octokit/request-error": "^7.0.1",
|
|
||||||
"@octokit/types": "^15.0.0",
|
|
||||||
"fast-content-type-parse": "^3.0.0",
|
|
||||||
"universal-user-agent": "^7.0.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 20"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/request-error": {
|
|
||||||
"version": "7.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.0.1.tgz",
|
|
||||||
"integrity": "sha512-CZpFwV4+1uBrxu7Cw8E5NCXDWFNf18MSY23TdxCBgjw1tXXHvTrZVsXlW8hgFTOLw8RQR1BBrMvYRtuyaijHMA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/types": "^15.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 20"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/types": {
|
|
||||||
"version": "15.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-15.0.1.tgz",
|
|
||||||
"integrity": "sha512-sdiirM93IYJ9ODDCBgmRPIboLbSkpLa5i+WLuXH8b8Atg+YMLAyLvDDhNWLV4OYd08tlvYfVm/dw88cqHWtw1Q==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/openapi-types": "^26.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@opentelemetry/api": {
|
"node_modules/@opentelemetry/api": {
|
||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.4.1.tgz",
|
||||||
@@ -1900,9 +1779,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "24.9.1",
|
"version": "24.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
|
||||||
"integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==",
|
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~7.16.0"
|
"undici-types": "~7.16.0"
|
||||||
@@ -2454,12 +2333,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||||
},
|
},
|
||||||
"node_modules/before-after-hook": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==",
|
|
||||||
"license": "Apache-2.0"
|
|
||||||
},
|
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "1.1.12",
|
"version": "1.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||||
@@ -2502,7 +2375,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"caniuse-lite": "^1.0.30001733",
|
"caniuse-lite": "^1.0.30001733",
|
||||||
"electron-to-chromium": "^1.5.199",
|
"electron-to-chromium": "^1.5.199",
|
||||||
@@ -3070,22 +2942,6 @@
|
|||||||
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
|
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fast-content-type-parse": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==",
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/fastify"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/fastify"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/fast-json-stable-stringify": {
|
"node_modules/fast-json-stable-stringify": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||||
@@ -3270,9 +3126,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/glob": {
|
"node_modules/glob": {
|
||||||
"version": "10.4.5",
|
"version": "10.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
|
||||||
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
"integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -3630,7 +3486,6 @@
|
|||||||
"integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==",
|
"integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jest/core": "30.2.0",
|
"@jest/core": "30.2.0",
|
||||||
"@jest/types": "30.2.0",
|
"@jest/types": "30.2.0",
|
||||||
@@ -4239,10 +4094,11 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/js-yaml": {
|
"node_modules/js-yaml": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
||||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"argparse": "^2.0.1"
|
"argparse": "^2.0.1"
|
||||||
},
|
},
|
||||||
@@ -4906,9 +4762,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/smol-toml": {
|
"node_modules/smol-toml": {
|
||||||
"version": "1.4.2",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.0.tgz",
|
||||||
"integrity": "sha512-rInDH6lCNiEyn3+hH8KVGFdbjc099j47+OSgbMrfDYX1CmXLfdKd7qi6IfcWj2wFxvSVkuI46M+wPGYfEOEj6g==",
|
"integrity": "sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 18"
|
"node": ">= 18"
|
||||||
@@ -5328,7 +5184,6 @@
|
|||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -5352,15 +5207,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/undici": {
|
"node_modules/undici": {
|
||||||
"version": "5.28.5",
|
"version": "7.22.0",
|
||||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.28.5.tgz",
|
"resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz",
|
||||||
"integrity": "sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==",
|
"integrity": "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@fastify/busboy": "^2.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0"
|
"node": ">=20.18.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/undici-types": {
|
"node_modules/undici-types": {
|
||||||
@@ -5369,12 +5220,6 @@
|
|||||||
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
|
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/universal-user-agent": {
|
|
||||||
"version": "7.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz",
|
|
||||||
"integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==",
|
|
||||||
"license": "ISC"
|
|
||||||
},
|
|
||||||
"node_modules/unrs-resolver": {
|
"node_modules/unrs-resolver": {
|
||||||
"version": "1.11.1",
|
"version": "1.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz",
|
"resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz",
|
||||||
@@ -5804,6 +5649,16 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"tunnel": "^0.0.6",
|
"tunnel": "^0.0.6",
|
||||||
"undici": "^5.25.4"
|
"undici": "^5.25.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"undici": {
|
||||||
|
"version": "5.29.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz",
|
||||||
|
"integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
|
||||||
|
"requires": {
|
||||||
|
"@fastify/busboy": "^2.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@actions/io": {
|
"@actions/io": {
|
||||||
@@ -6071,7 +5926,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz",
|
||||||
"integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
|
"integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@ampproject/remapping": "^2.2.0",
|
"@ampproject/remapping": "^2.2.0",
|
||||||
"@babel/code-frame": "^7.27.1",
|
"@babel/code-frame": "^7.27.1",
|
||||||
@@ -6394,74 +6248,74 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@biomejs/biome": {
|
"@biomejs/biome": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.8.tgz",
|
||||||
"integrity": "sha512-shdUY5H3S3tJVUWoVWo5ua+GdPW5lRHf+b0IwZ4OC1o2zOKQECZ6l2KbU6t89FNhtd3Qx5eg5N7/UsQWGQbAFw==",
|
"integrity": "sha512-Qjsgoe6FEBxWAUzwFGFrB+1+M8y/y5kwmg5CHac+GSVOdmOIqsAiXM5QMVGZJ1eCUCLlPZtq4aFAQ0eawEUuUA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@biomejs/cli-darwin-arm64": "2.3.0",
|
"@biomejs/cli-darwin-arm64": "2.3.8",
|
||||||
"@biomejs/cli-darwin-x64": "2.3.0",
|
"@biomejs/cli-darwin-x64": "2.3.8",
|
||||||
"@biomejs/cli-linux-arm64": "2.3.0",
|
"@biomejs/cli-linux-arm64": "2.3.8",
|
||||||
"@biomejs/cli-linux-arm64-musl": "2.3.0",
|
"@biomejs/cli-linux-arm64-musl": "2.3.8",
|
||||||
"@biomejs/cli-linux-x64": "2.3.0",
|
"@biomejs/cli-linux-x64": "2.3.8",
|
||||||
"@biomejs/cli-linux-x64-musl": "2.3.0",
|
"@biomejs/cli-linux-x64-musl": "2.3.8",
|
||||||
"@biomejs/cli-win32-arm64": "2.3.0",
|
"@biomejs/cli-win32-arm64": "2.3.8",
|
||||||
"@biomejs/cli-win32-x64": "2.3.0"
|
"@biomejs/cli-win32-x64": "2.3.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@biomejs/cli-darwin-arm64": {
|
"@biomejs/cli-darwin-arm64": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.8.tgz",
|
||||||
"integrity": "sha512-3cJVT0Z5pbTkoBmbjmDZTDFYxIkRcrs9sYVJbIBHU8E6qQxgXAaBfSVjjCreG56rfDuQBr43GzwzmaHPcu4vlw==",
|
"integrity": "sha512-HM4Zg9CGQ3txTPflxD19n8MFPrmUAjaC7PQdLkugeeC0cQ+PiVrd7i09gaBS/11QKsTDBJhVg85CEIK9f50Qww==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@biomejs/cli-darwin-x64": {
|
"@biomejs/cli-darwin-x64": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.3.8.tgz",
|
||||||
"integrity": "sha512-6LIkhglh3UGjuDqJXsK42qCA0XkD1Ke4K/raFOii7QQPbM8Pia7Qj2Hji4XuF2/R78hRmEx7uKJH3t/Y9UahtQ==",
|
"integrity": "sha512-lUDQ03D7y/qEao7RgdjWVGCu+BLYadhKTm40HkpJIi6kn8LSv5PAwRlew/DmwP4YZ9ke9XXoTIQDO1vAnbRZlA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@biomejs/cli-linux-arm64": {
|
"@biomejs/cli-linux-arm64": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.3.8.tgz",
|
||||||
"integrity": "sha512-uhAsbXySX7xsXahegDg5h3CDgfMcRsJvWLFPG0pjkylgBb9lErbK2C0UINW52zhwg0cPISB09lxHPxCau4e2xA==",
|
"integrity": "sha512-Uo1OJnIkJgSgF+USx970fsM/drtPcQ39I+JO+Fjsaa9ZdCN1oysQmy6oAGbyESlouz+rzEckLTF6DS7cWse95g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@biomejs/cli-linux-arm64-musl": {
|
"@biomejs/cli-linux-arm64-musl": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.3.8.tgz",
|
||||||
"integrity": "sha512-nDksoFdwZ2YrE7NiYDhtMhL2UgFn8Kb7Y0bYvnTAakHnqEdb4lKindtBc1f+xg2Snz0JQhJUYO7r9CDBosRU5w==",
|
"integrity": "sha512-PShR4mM0sjksUMyxbyPNMxoKFPVF48fU8Qe8Sfx6w6F42verbwRLbz+QiKNiDPRJwUoMG1nPM50OBL3aOnTevA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@biomejs/cli-linux-x64": {
|
"@biomejs/cli-linux-x64": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.3.8.tgz",
|
||||||
"integrity": "sha512-uxa8reA2s1VgoH8MhbGlCmMOt3JuSE1vJBifkh1ulaPiuk0SPx8cCdpnm9NWnTe2x/LfWInWx4sZ7muaXTPGGw==",
|
"integrity": "sha512-QDPMD5bQz6qOVb3kiBui0zKZXASLo0NIQ9JVJio5RveBEFgDgsvJFUvZIbMbUZT3T00M/1wdzwWXk4GIh0KaAw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@biomejs/cli-linux-x64-musl": {
|
"@biomejs/cli-linux-x64-musl": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.3.8.tgz",
|
||||||
"integrity": "sha512-+i9UcJwl99uAhtRQDz9jUAh+Xkb097eekxs/D9j4deWDg5/yB/jPWzISe1nBHvlzTXsdUSj0VvB4Go2DSpKIMw==",
|
"integrity": "sha512-YGLkqU91r1276uwSjiUD/xaVikdxgV1QpsicT0bIA1TaieM6E5ibMZeSyjQ/izBn4tKQthUSsVZacmoJfa3pDA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@biomejs/cli-win32-arm64": {
|
"@biomejs/cli-win32-arm64": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.3.8.tgz",
|
||||||
"integrity": "sha512-ynjmsJLIKrAjC3CCnKMMhzcnNy8dbQWjKfSU5YA0mIruTxBNMbkAJp+Pr2iV7/hFou+66ZSD/WV8hmLEmhUaXA==",
|
"integrity": "sha512-H4IoCHvL1fXKDrTALeTKMiE7GGWFAraDwBYFquE/L/5r1927Te0mYIGseXi4F+lrrwhSWbSGt5qPFswNoBaCxg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@biomejs/cli-win32-x64": {
|
"@biomejs/cli-win32-x64": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.3.8.tgz",
|
||||||
"integrity": "sha512-zOCYmCRVkWXc9v8P7OLbLlGGMxQTKMvi+5IC4v7O8DkjLCOHRzRVK/Lno2pGZNo0lzKM60pcQOhH8HVkXMQdFg==",
|
"integrity": "sha512-RguzimPoZWtBapfKhKjcWXBVI91tiSprqdBYu7tWhgN8pKRZhw24rFeNZTNf6UiBfjCYCi9eFQs/JzJZIhuK4w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
@@ -6565,9 +6419,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"js-yaml": {
|
"js-yaml": {
|
||||||
"version": "3.14.1",
|
"version": "3.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
|
||||||
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"argparse": "^1.0.7",
|
"argparse": "^1.0.7",
|
||||||
@@ -6886,94 +6740,6 @@
|
|||||||
"@tybys/wasm-util": "^0.10.0"
|
"@tybys/wasm-util": "^0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@octokit/auth-token": {
|
|
||||||
"version": "6.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz",
|
|
||||||
"integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w=="
|
|
||||||
},
|
|
||||||
"@octokit/core": {
|
|
||||||
"version": "7.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.5.tgz",
|
|
||||||
"integrity": "sha512-t54CUOsFMappY1Jbzb7fetWeO0n6K0k/4+/ZpkS+3Joz8I4VcvY9OiEBFRYISqaI2fq5sCiPtAjRDOzVYG8m+Q==",
|
|
||||||
"peer": true,
|
|
||||||
"requires": {
|
|
||||||
"@octokit/auth-token": "^6.0.0",
|
|
||||||
"@octokit/graphql": "^9.0.2",
|
|
||||||
"@octokit/request": "^10.0.4",
|
|
||||||
"@octokit/request-error": "^7.0.1",
|
|
||||||
"@octokit/types": "^15.0.0",
|
|
||||||
"before-after-hook": "^4.0.0",
|
|
||||||
"universal-user-agent": "^7.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@octokit/endpoint": {
|
|
||||||
"version": "11.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.1.tgz",
|
|
||||||
"integrity": "sha512-7P1dRAZxuWAOPI7kXfio88trNi/MegQ0IJD3vfgC3b+LZo1Qe6gRJc2v0mz2USWWJOKrB2h5spXCzGbw+fAdqA==",
|
|
||||||
"requires": {
|
|
||||||
"@octokit/types": "^15.0.0",
|
|
||||||
"universal-user-agent": "^7.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@octokit/graphql": {
|
|
||||||
"version": "9.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.2.tgz",
|
|
||||||
"integrity": "sha512-iz6KzZ7u95Fzy9Nt2L8cG88lGRMr/qy1Q36ih/XVzMIlPDMYwaNLE/ENhqmIzgPrlNWiYJkwmveEetvxAgFBJw==",
|
|
||||||
"requires": {
|
|
||||||
"@octokit/request": "^10.0.4",
|
|
||||||
"@octokit/types": "^15.0.0",
|
|
||||||
"universal-user-agent": "^7.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@octokit/openapi-types": {
|
|
||||||
"version": "26.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-26.0.0.tgz",
|
|
||||||
"integrity": "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA=="
|
|
||||||
},
|
|
||||||
"@octokit/plugin-paginate-rest": {
|
|
||||||
"version": "13.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-13.2.1.tgz",
|
|
||||||
"integrity": "sha512-Tj4PkZyIL6eBMYcG/76QGsedF0+dWVeLhYprTmuFVVxzDW7PQh23tM0TP0z+1MvSkxB29YFZwnUX+cXfTiSdyw==",
|
|
||||||
"requires": {
|
|
||||||
"@octokit/types": "^15.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@octokit/plugin-rest-endpoint-methods": {
|
|
||||||
"version": "16.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-16.1.1.tgz",
|
|
||||||
"integrity": "sha512-VztDkhM0ketQYSh5Im3IcKWFZl7VIrrsCaHbDINkdYeiiAsJzjhS2xRFCSJgfN6VOcsoW4laMtsmf3HcNqIimg==",
|
|
||||||
"requires": {
|
|
||||||
"@octokit/types": "^15.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@octokit/request": {
|
|
||||||
"version": "10.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.5.tgz",
|
|
||||||
"integrity": "sha512-TXnouHIYLtgDhKo+N6mXATnDBkV05VwbR0TtMWpgTHIoQdRQfCSzmy/LGqR1AbRMbijq/EckC/E3/ZNcU92NaQ==",
|
|
||||||
"requires": {
|
|
||||||
"@octokit/endpoint": "^11.0.1",
|
|
||||||
"@octokit/request-error": "^7.0.1",
|
|
||||||
"@octokit/types": "^15.0.0",
|
|
||||||
"fast-content-type-parse": "^3.0.0",
|
|
||||||
"universal-user-agent": "^7.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@octokit/request-error": {
|
|
||||||
"version": "7.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.0.1.tgz",
|
|
||||||
"integrity": "sha512-CZpFwV4+1uBrxu7Cw8E5NCXDWFNf18MSY23TdxCBgjw1tXXHvTrZVsXlW8hgFTOLw8RQR1BBrMvYRtuyaijHMA==",
|
|
||||||
"requires": {
|
|
||||||
"@octokit/types": "^15.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@octokit/types": {
|
|
||||||
"version": "15.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-15.0.1.tgz",
|
|
||||||
"integrity": "sha512-sdiirM93IYJ9ODDCBgmRPIboLbSkpLa5i+WLuXH8b8Atg+YMLAyLvDDhNWLV4OYd08tlvYfVm/dw88cqHWtw1Q==",
|
|
||||||
"requires": {
|
|
||||||
"@octokit/openapi-types": "^26.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@opentelemetry/api": {
|
"@opentelemetry/api": {
|
||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.4.1.tgz",
|
||||||
@@ -7125,9 +6891,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "24.9.1",
|
"version": "24.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
|
||||||
"integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==",
|
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"undici-types": "~7.16.0"
|
"undici-types": "~7.16.0"
|
||||||
}
|
}
|
||||||
@@ -7474,11 +7240,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||||
},
|
},
|
||||||
"before-after-hook": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="
|
|
||||||
},
|
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.12",
|
"version": "1.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||||
@@ -7502,7 +7263,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.2.tgz",
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.2.tgz",
|
||||||
"integrity": "sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA==",
|
"integrity": "sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"caniuse-lite": "^1.0.30001733",
|
"caniuse-lite": "^1.0.30001733",
|
||||||
"electron-to-chromium": "^1.5.199",
|
"electron-to-chromium": "^1.5.199",
|
||||||
@@ -7880,11 +7640,6 @@
|
|||||||
"jest-util": "30.2.0"
|
"jest-util": "30.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fast-content-type-parse": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg=="
|
|
||||||
},
|
|
||||||
"fast-json-stable-stringify": {
|
"fast-json-stable-stringify": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||||
@@ -8011,9 +7766,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"glob": {
|
"glob": {
|
||||||
"version": "10.4.5",
|
"version": "10.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
|
||||||
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
"integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"foreground-child": "^3.1.0",
|
"foreground-child": "^3.1.0",
|
||||||
@@ -8249,7 +8004,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/jest/-/jest-30.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/jest/-/jest-30.2.0.tgz",
|
||||||
"integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==",
|
"integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@jest/core": "30.2.0",
|
"@jest/core": "30.2.0",
|
||||||
"@jest/types": "30.2.0",
|
"@jest/types": "30.2.0",
|
||||||
@@ -8691,9 +8445,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"js-yaml": {
|
"js-yaml": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
||||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"argparse": "^2.0.1"
|
"argparse": "^2.0.1"
|
||||||
@@ -9130,9 +8884,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"smol-toml": {
|
"smol-toml": {
|
||||||
"version": "1.4.2",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.0.tgz",
|
||||||
"integrity": "sha512-rInDH6lCNiEyn3+hH8KVGFdbjc099j47+OSgbMrfDYX1CmXLfdKd7qi6IfcWj2wFxvSVkuI46M+wPGYfEOEj6g=="
|
"integrity": "sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw=="
|
||||||
},
|
},
|
||||||
"source-map": {
|
"source-map": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
@@ -9397,8 +9151,7 @@
|
|||||||
"version": "5.9.3",
|
"version": "5.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"uglify-js": {
|
"uglify-js": {
|
||||||
"version": "3.19.3",
|
"version": "3.19.3",
|
||||||
@@ -9408,23 +9161,15 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"undici": {
|
"undici": {
|
||||||
"version": "5.28.5",
|
"version": "7.22.0",
|
||||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.28.5.tgz",
|
"resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz",
|
||||||
"integrity": "sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==",
|
"integrity": "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg=="
|
||||||
"requires": {
|
|
||||||
"@fastify/busboy": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"undici-types": {
|
"undici-types": {
|
||||||
"version": "7.16.0",
|
"version": "7.16.0",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
|
||||||
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="
|
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="
|
||||||
},
|
},
|
||||||
"universal-user-agent": {
|
|
||||||
"version": "7.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz",
|
|
||||||
"integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A=="
|
|
||||||
},
|
|
||||||
"unrs-resolver": {
|
"unrs-resolver": {
|
||||||
"version": "1.11.1",
|
"version": "1.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz",
|
"resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz",
|
||||||
|
|||||||
22
package.json
22
package.json
@@ -7,17 +7,22 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"check": "biome check --write",
|
"check": "biome check --write",
|
||||||
"package": "ncc build -o dist/setup src/setup-uv.ts && ncc build -o dist/save-cache src/save-cache.ts && ncc build -o dist/update-known-versions src/update-known-versions.ts",
|
"package": "ncc build -o dist/setup src/setup-uv.ts && ncc build -o dist/save-cache src/save-cache.ts && ncc build -o dist/update-known-checksums src/update-known-checksums.ts",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"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-versions": "RUNNER_TEMP=known_versions node dist/update-known-versions/index.js src/download/checksum/known-versions.ts \"$(gh auth token)\"",
|
"update-known-checksums": "RUNNER_TEMP=known_versions node dist/update-known-checksums/index.js src/download/checksum/known-checksums.ts",
|
||||||
"all": "npm run build && npm run check && npm run package && npm test"
|
"all": "npm run build && npm run check && npm run package && npm test"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/astral-sh/setup-uv.git"
|
"url": "git+https://github.com/astral-sh/setup-uv.git"
|
||||||
},
|
},
|
||||||
"keywords": ["actions", "python", "setup", "uv"],
|
"keywords": [
|
||||||
|
"actions",
|
||||||
|
"python",
|
||||||
|
"setup",
|
||||||
|
"uv"
|
||||||
|
],
|
||||||
"author": "@eifinger",
|
"author": "@eifinger",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -27,17 +32,14 @@
|
|||||||
"@actions/glob": "^0.5.0",
|
"@actions/glob": "^0.5.0",
|
||||||
"@actions/io": "^1.1.3",
|
"@actions/io": "^1.1.3",
|
||||||
"@actions/tool-cache": "^2.0.2",
|
"@actions/tool-cache": "^2.0.2",
|
||||||
"@octokit/core": "^7.0.5",
|
|
||||||
"@octokit/plugin-paginate-rest": "^13.2.1",
|
|
||||||
"@octokit/plugin-rest-endpoint-methods": "^16.1.1",
|
|
||||||
"@renovatebot/pep440": "^4.2.1",
|
"@renovatebot/pep440": "^4.2.1",
|
||||||
"smol-toml": "^1.4.2",
|
"smol-toml": "^1.6.0",
|
||||||
"undici": "5.28.5"
|
"undici": "7.22.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "2.3.0",
|
"@biomejs/biome": "2.3.8",
|
||||||
"@types/js-yaml": "^4.0.9",
|
"@types/js-yaml": "^4.0.9",
|
||||||
"@types/node": "^24.9.1",
|
"@types/node": "^24.10.1",
|
||||||
"@types/semver": "^7.7.1",
|
"@types/semver": "^7.7.1",
|
||||||
"@vercel/ncc": "^0.38.4",
|
"@vercel/ncc": "^0.38.4",
|
||||||
"jest": "^30.2.0",
|
"jest": "^30.2.0",
|
||||||
|
|||||||
112
src/cache/restore-cache.ts
vendored
112
src/cache/restore-cache.ts
vendored
@@ -1,6 +1,5 @@
|
|||||||
import * as cache from "@actions/cache";
|
import * as cache from "@actions/cache";
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
import * as exec from "@actions/exec";
|
|
||||||
import { hashFiles } from "../hash/hash-files";
|
import { hashFiles } from "../hash/hash-files";
|
||||||
import {
|
import {
|
||||||
cacheDependencyGlob,
|
cacheDependencyGlob,
|
||||||
@@ -9,46 +8,75 @@ import {
|
|||||||
cacheSuffix,
|
cacheSuffix,
|
||||||
pruneCache,
|
pruneCache,
|
||||||
pythonDir,
|
pythonDir,
|
||||||
pythonVersion as pythonVersionInput,
|
|
||||||
restoreCache as shouldRestoreCache,
|
restoreCache as shouldRestoreCache,
|
||||||
workingDirectory,
|
|
||||||
} from "../utils/inputs";
|
} from "../utils/inputs";
|
||||||
import { getArch, getPlatform } from "../utils/platforms";
|
import { getArch, getOSNameVersion, getPlatform } from "../utils/platforms";
|
||||||
|
|
||||||
export const STATE_CACHE_KEY = "cache-key";
|
export const STATE_CACHE_KEY = "cache-key";
|
||||||
export const STATE_CACHE_MATCHED_KEY = "cache-matched-key";
|
export const STATE_CACHE_MATCHED_KEY = "cache-matched-key";
|
||||||
const CACHE_VERSION = "1";
|
export const STATE_PYTHON_CACHE_MATCHED_KEY = "python-cache-matched-key";
|
||||||
|
|
||||||
export async function restoreCache(): Promise<void> {
|
const CACHE_VERSION = "2";
|
||||||
const cacheKey = await computeKeys();
|
|
||||||
|
export async function restoreCache(pythonVersion?: string): Promise<void> {
|
||||||
|
const cacheKey = await computeKeys(pythonVersion);
|
||||||
core.saveState(STATE_CACHE_KEY, cacheKey);
|
core.saveState(STATE_CACHE_KEY, cacheKey);
|
||||||
|
core.setOutput("cache-key", cacheKey);
|
||||||
|
|
||||||
if (!shouldRestoreCache) {
|
if (!shouldRestoreCache) {
|
||||||
core.info("restore-cache is false. Skipping restore cache step.");
|
core.info("restore-cache is false. Skipping restore cache step.");
|
||||||
|
core.setOutput("python-cache-hit", false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let matchedKey: string | undefined;
|
if (cacheLocalPath === undefined) {
|
||||||
core.info(
|
throw new Error(
|
||||||
`Trying to restore uv cache from GitHub Actions cache with key: ${cacheKey}`,
|
"cache-local-path is not set. Cannot restore cache without a valid cache path.",
|
||||||
);
|
);
|
||||||
const cachePaths = [cacheLocalPath];
|
|
||||||
if (cachePython) {
|
|
||||||
cachePaths.push(pythonDir);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await restoreCacheFromKey(
|
||||||
|
cacheKey,
|
||||||
|
cacheLocalPath.path,
|
||||||
|
STATE_CACHE_MATCHED_KEY,
|
||||||
|
"cache-hit",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (cachePython) {
|
||||||
|
await restoreCacheFromKey(
|
||||||
|
`${cacheKey}-python`,
|
||||||
|
pythonDir,
|
||||||
|
STATE_PYTHON_CACHE_MATCHED_KEY,
|
||||||
|
"python-cache-hit",
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
core.setOutput("python-cache-hit", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function restoreCacheFromKey(
|
||||||
|
cacheKey: string,
|
||||||
|
cachePath: string,
|
||||||
|
stateKey: string,
|
||||||
|
outputKey: string,
|
||||||
|
): Promise<void> {
|
||||||
|
core.info(
|
||||||
|
`Trying to restore cache from GitHub Actions cache with key: ${cacheKey}`,
|
||||||
|
);
|
||||||
|
let matchedKey: string | undefined;
|
||||||
try {
|
try {
|
||||||
matchedKey = await cache.restoreCache(cachePaths, cacheKey);
|
matchedKey = await cache.restoreCache([cachePath], cacheKey);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const message = (err as Error).message;
|
const message = (err as Error).message;
|
||||||
core.warning(message);
|
core.warning(message);
|
||||||
core.setOutput("cache-hit", false);
|
core.setOutput(outputKey, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMatchResult(matchedKey, cacheKey);
|
handleMatchResult(matchedKey, cacheKey, stateKey, outputKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function computeKeys(): Promise<string> {
|
async function computeKeys(pythonVersion?: string): Promise<string> {
|
||||||
let cacheDependencyPathHash = "-";
|
let cacheDependencyPathHash = "-";
|
||||||
if (cacheDependencyGlob !== "") {
|
if (cacheDependencyGlob !== "") {
|
||||||
core.info(
|
core.info(
|
||||||
@@ -65,57 +93,27 @@ async function computeKeys(): Promise<string> {
|
|||||||
cacheDependencyPathHash = "-no-dependency-glob";
|
cacheDependencyPathHash = "-no-dependency-glob";
|
||||||
}
|
}
|
||||||
const suffix = cacheSuffix ? `-${cacheSuffix}` : "";
|
const suffix = cacheSuffix ? `-${cacheSuffix}` : "";
|
||||||
const pythonVersion = await getPythonVersion();
|
const version = pythonVersion ?? "unknown";
|
||||||
const platform = await getPlatform();
|
const platform = await getPlatform();
|
||||||
|
const osNameVersion = getOSNameVersion();
|
||||||
const pruned = pruneCache ? "-pruned" : "";
|
const pruned = pruneCache ? "-pruned" : "";
|
||||||
const python = cachePython ? "-py" : "";
|
const python = cachePython ? "-py" : "";
|
||||||
return `setup-uv-${CACHE_VERSION}-${getArch()}-${platform}-${pythonVersion}${pruned}${python}${cacheDependencyPathHash}${suffix}`;
|
return `setup-uv-${CACHE_VERSION}-${getArch()}-${platform}-${osNameVersion}-${version}${pruned}${python}${cacheDependencyPathHash}${suffix}`;
|
||||||
}
|
|
||||||
|
|
||||||
async function getPythonVersion(): Promise<string> {
|
|
||||||
if (pythonVersionInput !== "") {
|
|
||||||
return pythonVersionInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
let output = "";
|
|
||||||
const options: exec.ExecOptions = {
|
|
||||||
listeners: {
|
|
||||||
stdout: (data: Buffer) => {
|
|
||||||
output += data.toString();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
silent: !core.isDebug(),
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
const execArgs = ["python", "find", "--directory", workingDirectory];
|
|
||||||
await exec.exec("uv", execArgs, options);
|
|
||||||
const pythonPath = output.trim();
|
|
||||||
|
|
||||||
output = "";
|
|
||||||
await exec.exec(pythonPath, ["--version"], options);
|
|
||||||
// output is like "Python 3.8.10"
|
|
||||||
return output.split(" ")[1].trim();
|
|
||||||
} catch (error) {
|
|
||||||
const err = error as Error;
|
|
||||||
core.debug(`Failed to get python version from uv. Error: ${err.message}`);
|
|
||||||
return "unknown";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMatchResult(
|
function handleMatchResult(
|
||||||
matchedKey: string | undefined,
|
matchedKey: string | undefined,
|
||||||
primaryKey: string,
|
primaryKey: string,
|
||||||
|
stateKey: string,
|
||||||
|
outputKey: string,
|
||||||
): void {
|
): void {
|
||||||
if (!matchedKey) {
|
if (!matchedKey) {
|
||||||
core.info(`No GitHub Actions cache found for key: ${primaryKey}`);
|
core.info(`No GitHub Actions cache found for key: ${primaryKey}`);
|
||||||
core.setOutput("cache-hit", false);
|
core.setOutput(outputKey, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
core.saveState(STATE_CACHE_MATCHED_KEY, matchedKey);
|
core.saveState(stateKey, matchedKey);
|
||||||
core.info(
|
core.info(`cache restored from GitHub Actions cache with key: ${matchedKey}`);
|
||||||
`uv cache restored from GitHub Actions cache with key: ${matchedKey}`,
|
core.setOutput(outputKey, true);
|
||||||
);
|
|
||||||
core.setOutput("cache-hit", true);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,33 +6,35 @@ import type { Architecture, Platform } from "../../utils/platforms";
|
|||||||
import { KNOWN_CHECKSUMS } from "./known-checksums";
|
import { KNOWN_CHECKSUMS } from "./known-checksums";
|
||||||
|
|
||||||
export async function validateChecksum(
|
export async function validateChecksum(
|
||||||
checkSum: string | undefined,
|
checksum: string | undefined,
|
||||||
downloadPath: string,
|
downloadPath: string,
|
||||||
arch: Architecture,
|
arch: Architecture,
|
||||||
platform: Platform,
|
platform: Platform,
|
||||||
version: string,
|
version: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
let isValid: boolean | undefined;
|
const key = `${arch}-${platform}-${version}`;
|
||||||
if (checkSum !== undefined && checkSum !== "") {
|
const hasProvidedChecksum = checksum !== undefined && checksum !== "";
|
||||||
isValid = await validateFileCheckSum(downloadPath, checkSum);
|
const checksumToUse = hasProvidedChecksum ? checksum : KNOWN_CHECKSUMS[key];
|
||||||
} else {
|
|
||||||
core.debug("Checksum not provided. Checking known checksums.");
|
if (checksumToUse === undefined) {
|
||||||
const key = `${arch}-${platform}-${version}`;
|
core.debug(`No checksum found for ${key}.`);
|
||||||
if (key in KNOWN_CHECKSUMS) {
|
return;
|
||||||
const knownChecksum = KNOWN_CHECKSUMS[`${arch}-${platform}-${version}`];
|
|
||||||
core.debug(`Checking checksum for ${arch}-${platform}-${version}.`);
|
|
||||||
isValid = await validateFileCheckSum(downloadPath, knownChecksum);
|
|
||||||
} else {
|
|
||||||
core.debug(`No known checksum found for ${key}.`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isValid === false) {
|
const checksumSource = hasProvidedChecksum
|
||||||
throw new Error(`Checksum for ${downloadPath} did not match ${checkSum}.`);
|
? "provided checksum"
|
||||||
}
|
: `KNOWN_CHECKSUMS entry for ${key}`;
|
||||||
if (isValid === true) {
|
|
||||||
core.debug(`Checksum for ${downloadPath} is valid.`);
|
core.debug(`Validating checksum using ${checksumSource}.`);
|
||||||
|
const isValid = await validateFileCheckSum(downloadPath, checksumToUse);
|
||||||
|
|
||||||
|
if (!isValid) {
|
||||||
|
throw new Error(
|
||||||
|
`Checksum for ${downloadPath} did not match ${checksumToUse}.`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
core.debug(`Checksum for ${downloadPath} is valid.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function validateFileCheckSum(
|
async function validateFileCheckSum(
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,59 +1,34 @@
|
|||||||
import { promises as fs } from "node:fs";
|
import { promises as fs } from "node:fs";
|
||||||
import * as tc from "@actions/tool-cache";
|
|
||||||
import { KNOWN_CHECKSUMS } from "./known-checksums";
|
export interface ChecksumEntry {
|
||||||
|
key: string;
|
||||||
|
checksum: string;
|
||||||
|
}
|
||||||
|
|
||||||
export async function updateChecksums(
|
export async function updateChecksums(
|
||||||
filePath: string,
|
filePath: string,
|
||||||
downloadUrls: string[],
|
checksumEntries: ChecksumEntry[],
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await fs.rm(filePath);
|
const deduplicatedEntries = new Map<string, string>();
|
||||||
await fs.appendFile(
|
|
||||||
filePath,
|
for (const entry of checksumEntries) {
|
||||||
"// AUTOGENERATED_DO_NOT_EDIT\nexport const KNOWN_CHECKSUMS: { [key: string]: string } = {\n",
|
if (deduplicatedEntries.has(entry.key)) {
|
||||||
);
|
|
||||||
let firstLine = true;
|
|
||||||
for (const downloadUrl of downloadUrls) {
|
|
||||||
const key = getKey(downloadUrl);
|
|
||||||
if (key === undefined) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const checksum = await getOrDownloadChecksum(key, downloadUrl);
|
|
||||||
if (!firstLine) {
|
|
||||||
await fs.appendFile(filePath, ",\n");
|
|
||||||
}
|
|
||||||
await fs.appendFile(filePath, ` "${key}":\n "${checksum}"`);
|
|
||||||
firstLine = false;
|
|
||||||
}
|
|
||||||
await fs.appendFile(filePath, ",\n};\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
function getKey(downloadUrl: string): string | undefined {
|
deduplicatedEntries.set(entry.key, entry.checksum);
|
||||||
// https://github.com/astral-sh/uv/releases/download/0.3.2/uv-aarch64-apple-darwin.tar.gz.sha256
|
|
||||||
const parts = downloadUrl.split("/");
|
|
||||||
const fileName = parts[parts.length - 1];
|
|
||||||
if (fileName.startsWith("source")) {
|
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
const name = fileName.split(".")[0].split("uv-")[1];
|
|
||||||
const version = parts[parts.length - 2];
|
|
||||||
return `${name}-${version}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getOrDownloadChecksum(
|
const body = [...deduplicatedEntries.entries()]
|
||||||
key: string,
|
.map(([key, checksum]) => ` "${key}":\n "${checksum}"`)
|
||||||
downloadUrl: string,
|
.join(",\n");
|
||||||
): Promise<string> {
|
|
||||||
let checksum = "";
|
|
||||||
if (key in KNOWN_CHECKSUMS) {
|
|
||||||
checksum = KNOWN_CHECKSUMS[key];
|
|
||||||
} else {
|
|
||||||
const content = await downloadAssetContent(downloadUrl);
|
|
||||||
checksum = content.split(" ")[0].trim();
|
|
||||||
}
|
|
||||||
return checksum;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function downloadAssetContent(downloadUrl: string): Promise<string> {
|
const content =
|
||||||
const downloadPath = await tc.downloadTool(downloadUrl);
|
"// AUTOGENERATED_DO_NOT_EDIT\n" +
|
||||||
const content = await fs.readFile(downloadPath, "utf8");
|
"export const KNOWN_CHECKSUMS: { [key: string]: string } = {\n" +
|
||||||
return content;
|
body +
|
||||||
|
(body === "" ? "" : ",\n") +
|
||||||
|
"};\n";
|
||||||
|
|
||||||
|
await fs.writeFile(filePath, content);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,20 +2,21 @@ import { promises as fs } from "node:fs";
|
|||||||
import * as path from "node:path";
|
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 type { Endpoints } from "@octokit/types";
|
|
||||||
import * as pep440 from "@renovatebot/pep440";
|
import * as pep440 from "@renovatebot/pep440";
|
||||||
import * as semver from "semver";
|
import * as semver from "semver";
|
||||||
import { OWNER, REPO, TOOL_CACHE_NAME } from "../utils/constants";
|
import { TOOL_CACHE_NAME, VERSIONS_NDJSON_URL } from "../utils/constants";
|
||||||
import { Octokit } from "../utils/octokit";
|
|
||||||
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 {
|
import {
|
||||||
getDownloadUrl,
|
getAllVersions as getAllManifestVersions,
|
||||||
getLatestKnownVersion as getLatestVersionInManifest,
|
getLatestKnownVersion as getLatestVersionInManifest,
|
||||||
|
getManifestArtifact,
|
||||||
} from "./version-manifest";
|
} from "./version-manifest";
|
||||||
|
import {
|
||||||
type Release =
|
getAllVersions as getAllVersionsFromNdjson,
|
||||||
Endpoints["GET /repos/{owner}/{repo}/releases"]["response"]["data"][number];
|
getArtifact as getArtifactFromNdjson,
|
||||||
|
getLatestVersion as getLatestVersionFromNdjson,
|
||||||
|
} from "./versions-client";
|
||||||
|
|
||||||
export function tryGetFromToolCache(
|
export function tryGetFromToolCache(
|
||||||
arch: Architecture,
|
arch: Architecture,
|
||||||
@@ -32,19 +33,26 @@ export function tryGetFromToolCache(
|
|||||||
return { installedPath, version: resolvedVersion };
|
return { installedPath, version: resolvedVersion };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function downloadVersionFromGithub(
|
export async function downloadVersionFromNdjson(
|
||||||
platform: Platform,
|
platform: Platform,
|
||||||
arch: Architecture,
|
arch: Architecture,
|
||||||
version: string,
|
version: string,
|
||||||
checkSum: string | undefined,
|
checkSum: string | undefined,
|
||||||
githubToken: string,
|
githubToken: string,
|
||||||
): Promise<{ version: string; cachedToolDir: string }> {
|
): Promise<{ version: string; cachedToolDir: string }> {
|
||||||
const artifact = `uv-${arch}-${platform}`;
|
const artifact = await getArtifactFromNdjson(version, arch, platform);
|
||||||
const extension = getExtension(platform);
|
|
||||||
const downloadUrl = `https://github.com/${OWNER}/${REPO}/releases/download/${version}/${artifact}${extension}`;
|
if (!artifact) {
|
||||||
|
throw new Error(
|
||||||
|
`Could not find artifact for version ${version}, arch ${arch}, platform ${platform} in ${VERSIONS_NDJSON_URL} .`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For the default astral-sh/versions source, checksum validation relies on
|
||||||
|
// user input or the built-in KNOWN_CHECKSUMS table, not NDJSON sha256 values.
|
||||||
return await downloadVersion(
|
return await downloadVersion(
|
||||||
downloadUrl,
|
artifact.url,
|
||||||
artifact,
|
`uv-${arch}-${platform}`,
|
||||||
platform,
|
platform,
|
||||||
arch,
|
arch,
|
||||||
version,
|
version,
|
||||||
@@ -54,38 +62,32 @@ export async function downloadVersionFromGithub(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function downloadVersionFromManifest(
|
export async function downloadVersionFromManifest(
|
||||||
manifestUrl: string | undefined,
|
manifestUrl: string,
|
||||||
platform: Platform,
|
platform: Platform,
|
||||||
arch: Architecture,
|
arch: Architecture,
|
||||||
version: string,
|
version: string,
|
||||||
checkSum: string | undefined,
|
checkSum: string | undefined,
|
||||||
githubToken: string,
|
githubToken: string,
|
||||||
): Promise<{ version: string; cachedToolDir: string }> {
|
): Promise<{ version: string; cachedToolDir: string }> {
|
||||||
const downloadUrl = await getDownloadUrl(
|
const artifact = await getManifestArtifact(
|
||||||
manifestUrl,
|
manifestUrl,
|
||||||
version,
|
version,
|
||||||
arch,
|
arch,
|
||||||
platform,
|
platform,
|
||||||
);
|
);
|
||||||
if (!downloadUrl) {
|
if (!artifact) {
|
||||||
core.info(
|
throw new Error(
|
||||||
`manifest-file does not contain version ${version}, arch ${arch}, platform ${platform}. Falling back to GitHub releases.`,
|
`manifest-file does not contain version ${version}, arch ${arch}, platform ${platform}.`,
|
||||||
);
|
|
||||||
return await downloadVersionFromGithub(
|
|
||||||
platform,
|
|
||||||
arch,
|
|
||||||
version,
|
|
||||||
checkSum,
|
|
||||||
githubToken,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return await downloadVersion(
|
return await downloadVersion(
|
||||||
downloadUrl,
|
artifact.downloadUrl,
|
||||||
`uv-${arch}-${platform}`,
|
`uv-${arch}-${platform}`,
|
||||||
platform,
|
platform,
|
||||||
arch,
|
arch,
|
||||||
version,
|
version,
|
||||||
checkSum,
|
resolveChecksum(checkSum, artifact.checksum),
|
||||||
githubToken,
|
githubToken,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -96,7 +98,7 @@ async function downloadVersion(
|
|||||||
platform: Platform,
|
platform: Platform,
|
||||||
arch: Architecture,
|
arch: Architecture,
|
||||||
version: string,
|
version: string,
|
||||||
checkSum: string | undefined,
|
checksum: string | undefined,
|
||||||
githubToken: string,
|
githubToken: string,
|
||||||
): Promise<{ version: string; cachedToolDir: string }> {
|
): Promise<{ version: string; cachedToolDir: string }> {
|
||||||
core.info(`Downloading uv from "${downloadUrl}" ...`);
|
core.info(`Downloading uv from "${downloadUrl}" ...`);
|
||||||
@@ -105,14 +107,14 @@ async function downloadVersion(
|
|||||||
undefined,
|
undefined,
|
||||||
githubToken,
|
githubToken,
|
||||||
);
|
);
|
||||||
await validateChecksum(checkSum, downloadPath, arch, platform, version);
|
await validateChecksum(checksum, downloadPath, arch, platform, version);
|
||||||
|
|
||||||
let uvDir: string;
|
let uvDir: string;
|
||||||
if (platform === "pc-windows-msvc") {
|
if (platform === "pc-windows-msvc") {
|
||||||
// On windows extracting the zip does not create an intermediate directory
|
// On windows extracting the zip does not create an intermediate directory.
|
||||||
try {
|
try {
|
||||||
// Try tar first as it's much faster, but only bsdtar supports zip files,
|
// Try tar first as it's much faster, but only bsdtar supports zip files,
|
||||||
// so this my fail if another tar, like gnu tar, ends up being used.
|
// so this may fail if another tar, like gnu tar, ends up being used.
|
||||||
uvDir = await tc.extractTar(downloadPath, undefined, "x");
|
uvDir = await tc.extractTar(downloadPath, undefined, "x");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
core.info(
|
core.info(
|
||||||
@@ -127,6 +129,7 @@ async function downloadVersion(
|
|||||||
const extractedDir = await tc.extractTar(downloadPath);
|
const extractedDir = await tc.extractTar(downloadPath);
|
||||||
uvDir = path.join(extractedDir, artifactName);
|
uvDir = path.join(extractedDir, artifactName);
|
||||||
}
|
}
|
||||||
|
|
||||||
const cachedToolDir = await tc.cacheDir(
|
const cachedToolDir = await tc.cacheDir(
|
||||||
uvDir,
|
uvDir,
|
||||||
TOOL_CACHE_NAME,
|
TOOL_CACHE_NAME,
|
||||||
@@ -136,14 +139,22 @@ async function downloadVersion(
|
|||||||
return { cachedToolDir, version: version };
|
return { cachedToolDir, version: version };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveChecksum(
|
||||||
|
checkSum: string | undefined,
|
||||||
|
manifestChecksum?: string,
|
||||||
|
): string | undefined {
|
||||||
|
return checkSum !== undefined && checkSum !== ""
|
||||||
|
? checkSum
|
||||||
|
: manifestChecksum;
|
||||||
|
}
|
||||||
|
|
||||||
function getExtension(platform: Platform): string {
|
function getExtension(platform: Platform): string {
|
||||||
return platform === "pc-windows-msvc" ? ".zip" : ".tar.gz";
|
return platform === "pc-windows-msvc" ? ".zip" : ".tar.gz";
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function resolveVersion(
|
export async function resolveVersion(
|
||||||
versionInput: string,
|
versionInput: string,
|
||||||
manifestFile: string | undefined,
|
manifestUrl: string | undefined,
|
||||||
githubToken: string,
|
|
||||||
resolutionStrategy: "highest" | "lowest" = "highest",
|
resolutionStrategy: "highest" | "lowest" = "highest",
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
core.debug(`Resolving version: ${versionInput}`);
|
core.debug(`Resolving version: ${versionInput}`);
|
||||||
@@ -155,15 +166,15 @@ export async function resolveVersion(
|
|||||||
if (resolveVersionSpecifierToLatest) {
|
if (resolveVersionSpecifierToLatest) {
|
||||||
core.info("Found minimum version specifier, using latest version");
|
core.info("Found minimum version specifier, using latest version");
|
||||||
}
|
}
|
||||||
if (manifestFile) {
|
if (manifestUrl !== undefined) {
|
||||||
version =
|
version =
|
||||||
versionInput === "latest" || resolveVersionSpecifierToLatest
|
versionInput === "latest" || resolveVersionSpecifierToLatest
|
||||||
? await getLatestVersionInManifest(manifestFile)
|
? await getLatestVersionInManifest(manifestUrl)
|
||||||
: versionInput;
|
: versionInput;
|
||||||
} else {
|
} else {
|
||||||
version =
|
version =
|
||||||
versionInput === "latest" || resolveVersionSpecifierToLatest
|
versionInput === "latest" || resolveVersionSpecifierToLatest
|
||||||
? await getLatestVersion(githubToken)
|
? await getLatestVersionFromNdjson()
|
||||||
: versionInput;
|
: versionInput;
|
||||||
}
|
}
|
||||||
if (tc.isExplicitVersion(version)) {
|
if (tc.isExplicitVersion(version)) {
|
||||||
@@ -175,91 +186,33 @@ export async function resolveVersion(
|
|||||||
}
|
}
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
const availableVersions = await getAvailableVersions(githubToken);
|
|
||||||
|
const availableVersions = await getAvailableVersions(manifestUrl);
|
||||||
core.debug(`Available versions: ${availableVersions}`);
|
core.debug(`Available versions: ${availableVersions}`);
|
||||||
const resolvedVersion =
|
const resolvedVersion =
|
||||||
resolutionStrategy === "lowest"
|
resolutionStrategy === "lowest"
|
||||||
? minSatisfying(availableVersions, version)
|
? minSatisfying(availableVersions, version)
|
||||||
: maxSatisfying(availableVersions, version);
|
: maxSatisfying(availableVersions, version);
|
||||||
|
|
||||||
if (resolvedVersion === undefined) {
|
if (resolvedVersion === undefined) {
|
||||||
throw new Error(`No version found for ${version}`);
|
throw new Error(`No version found for ${version}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolvedVersion;
|
return resolvedVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAvailableVersions(githubToken: string): Promise<string[]> {
|
async function getAvailableVersions(
|
||||||
core.info("Getting available versions from GitHub API...");
|
manifestUrl: string | undefined,
|
||||||
try {
|
): Promise<string[]> {
|
||||||
const octokit = new Octokit({
|
if (manifestUrl !== undefined) {
|
||||||
auth: githubToken,
|
core.info(
|
||||||
});
|
`Getting available versions from manifest-file ${manifestUrl} ...`,
|
||||||
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 Octokit();
|
|
||||||
return await getReleaseTagNames(octokit);
|
|
||||||
}
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getReleaseTagNames(octokit: Octokit): Promise<string[]> {
|
|
||||||
const response: Release[] = await octokit.paginate(
|
|
||||||
octokit.rest.repos.listReleases,
|
|
||||||
{
|
|
||||||
owner: OWNER,
|
|
||||||
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 await getAllManifestVersions(manifestUrl);
|
||||||
return releaseTagNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getLatestVersion(githubToken: string) {
|
|
||||||
core.info("Getting latest version from GitHub API...");
|
|
||||||
const octokit = new Octokit({
|
|
||||||
auth: githubToken,
|
|
||||||
});
|
|
||||||
|
|
||||||
let latestRelease: { tag_name: string } | undefined;
|
|
||||||
try {
|
|
||||||
latestRelease = await getLatestRelease(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 Octokit();
|
|
||||||
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) {
|
core.info(`Getting available versions from ${VERSIONS_NDJSON_URL} ...`);
|
||||||
throw new Error("Could not determine latest release.");
|
return await getAllVersionsFromNdjson();
|
||||||
}
|
|
||||||
core.debug(`Latest version: ${latestRelease.tag_name}`);
|
|
||||||
return latestRelease.tag_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getLatestRelease(octokit: Octokit) {
|
|
||||||
const { data: latestRelease } = await octokit.rest.repos.getLatestRelease({
|
|
||||||
owner: OWNER,
|
|
||||||
repo: REPO,
|
|
||||||
});
|
|
||||||
return latestRelease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function maxSatisfying(
|
function maxSatisfying(
|
||||||
|
|||||||
80
src/download/legacy-version-manifest.ts
Normal file
80
src/download/legacy-version-manifest.ts
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
|
export interface ManifestEntry {
|
||||||
|
arch: string;
|
||||||
|
platform: string;
|
||||||
|
version: string;
|
||||||
|
downloadUrl: string;
|
||||||
|
checksum?: string;
|
||||||
|
variant?: string;
|
||||||
|
archiveFormat?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LegacyManifestEntry {
|
||||||
|
arch: string;
|
||||||
|
platform: string;
|
||||||
|
version: string;
|
||||||
|
downloadUrl: string;
|
||||||
|
checksum?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const warnedLegacyManifestUrls = new Set<string>();
|
||||||
|
|
||||||
|
export function parseLegacyManifestEntries(
|
||||||
|
parsedEntries: unknown[],
|
||||||
|
manifestUrl: string,
|
||||||
|
): ManifestEntry[] {
|
||||||
|
warnAboutLegacyManifestFormat(manifestUrl);
|
||||||
|
|
||||||
|
return parsedEntries.map((entry, index) => {
|
||||||
|
if (!isLegacyManifestEntry(entry)) {
|
||||||
|
throw new Error(
|
||||||
|
`Invalid legacy manifest-file entry at index ${index} in ${manifestUrl}.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
arch: entry.arch,
|
||||||
|
checksum: entry.checksum,
|
||||||
|
downloadUrl: entry.downloadUrl,
|
||||||
|
platform: entry.platform,
|
||||||
|
version: entry.version,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearLegacyManifestWarnings(): void {
|
||||||
|
warnedLegacyManifestUrls.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
function warnAboutLegacyManifestFormat(manifestUrl: string): void {
|
||||||
|
if (warnedLegacyManifestUrls.has(manifestUrl)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
warnedLegacyManifestUrls.add(manifestUrl);
|
||||||
|
core.warning(
|
||||||
|
`manifest-file ${manifestUrl} uses the legacy JSON array format, which is deprecated. Please migrate to the astral-sh/versions NDJSON format before the next major release.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isLegacyManifestEntry(value: unknown): value is LegacyManifestEntry {
|
||||||
|
if (!isRecord(value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const checksumIsValid =
|
||||||
|
typeof value.checksum === "string" || value.checksum === undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
typeof value.arch === "string" &&
|
||||||
|
checksumIsValid &&
|
||||||
|
typeof value.downloadUrl === "string" &&
|
||||||
|
typeof value.platform === "string" &&
|
||||||
|
typeof value.version === "string"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||||
|
return typeof value === "object" && value !== null;
|
||||||
|
}
|
||||||
39
src/download/variant-selection.ts
Normal file
39
src/download/variant-selection.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
interface VariantAwareEntry {
|
||||||
|
variant?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function selectDefaultVariant<T extends VariantAwareEntry>(
|
||||||
|
entries: T[],
|
||||||
|
duplicateEntryDescription: string,
|
||||||
|
): T {
|
||||||
|
const firstEntry = entries[0];
|
||||||
|
if (firstEntry === undefined) {
|
||||||
|
throw new Error("selectDefaultVariant requires at least one candidate.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entries.length === 1) {
|
||||||
|
return firstEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultEntries = entries.filter((entry) =>
|
||||||
|
isDefaultVariant(entry.variant),
|
||||||
|
);
|
||||||
|
if (defaultEntries.length === 1) {
|
||||||
|
return defaultEntries[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
`${duplicateEntryDescription} with variants ${formatVariants(entries)}. setup-uv currently requires a single default variant for duplicate platform entries.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isDefaultVariant(variant: string | undefined): boolean {
|
||||||
|
return variant === undefined || variant === "default";
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatVariants<T extends VariantAwareEntry>(entries: T[]): string {
|
||||||
|
return entries
|
||||||
|
.map((entry) => entry.variant ?? "default")
|
||||||
|
.sort((left, right) => left.localeCompare(right))
|
||||||
|
.join(", ");
|
||||||
|
}
|
||||||
@@ -1,91 +1,169 @@
|
|||||||
import { promises as fs } from "node:fs";
|
|
||||||
import { join } from "node:path";
|
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
import * as semver from "semver";
|
import * as semver from "semver";
|
||||||
import { fetch } from "../utils/fetch";
|
import { fetch } from "../utils/fetch";
|
||||||
|
import {
|
||||||
|
clearLegacyManifestWarnings,
|
||||||
|
type ManifestEntry,
|
||||||
|
parseLegacyManifestEntries,
|
||||||
|
} from "./legacy-version-manifest";
|
||||||
|
import { selectDefaultVariant } from "./variant-selection";
|
||||||
|
import { type NdjsonVersion, parseVersionData } from "./versions-client";
|
||||||
|
|
||||||
const localManifestFile = join(__dirname, "..", "..", "version-manifest.json");
|
export interface ManifestArtifact {
|
||||||
|
|
||||||
interface ManifestEntry {
|
|
||||||
version: string;
|
|
||||||
artifactName: string;
|
|
||||||
arch: string;
|
|
||||||
platform: string;
|
|
||||||
downloadUrl: string;
|
downloadUrl: string;
|
||||||
|
checksum?: string;
|
||||||
|
archiveFormat?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cachedManifestEntries = new Map<string, ManifestEntry[]>();
|
||||||
|
|
||||||
export async function getLatestKnownVersion(
|
export async function getLatestKnownVersion(
|
||||||
manifestUrl: string | undefined,
|
manifestUrl: string,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const manifestEntries = await getManifestEntries(manifestUrl);
|
const versions = await getAllVersions(manifestUrl);
|
||||||
return manifestEntries.reduce((a, b) =>
|
const latestVersion = versions.reduce((latest, current) =>
|
||||||
semver.gt(a.version, b.version) ? a : b,
|
semver.gt(current, latest) ? current : latest,
|
||||||
).version;
|
);
|
||||||
|
|
||||||
|
return latestVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getDownloadUrl(
|
export async function getAllVersions(manifestUrl: string): Promise<string[]> {
|
||||||
manifestUrl: string | undefined,
|
const manifestEntries = await getManifestEntries(manifestUrl);
|
||||||
|
return [...new Set(manifestEntries.map((entry) => entry.version))];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getManifestArtifact(
|
||||||
|
manifestUrl: string,
|
||||||
version: string,
|
version: string,
|
||||||
arch: string,
|
arch: string,
|
||||||
platform: string,
|
platform: string,
|
||||||
): Promise<string | undefined> {
|
): Promise<ManifestArtifact | undefined> {
|
||||||
const manifestEntries = await getManifestEntries(manifestUrl);
|
const manifestEntries = await getManifestEntries(manifestUrl);
|
||||||
const entry = manifestEntries.find(
|
const entry = selectManifestEntry(
|
||||||
(entry) =>
|
manifestEntries,
|
||||||
entry.version === version &&
|
manifestUrl,
|
||||||
entry.arch === arch &&
|
version,
|
||||||
entry.platform === platform,
|
arch,
|
||||||
|
platform,
|
||||||
);
|
);
|
||||||
return entry ? entry.downloadUrl : undefined;
|
|
||||||
|
if (!entry) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
archiveFormat: entry.archiveFormat,
|
||||||
|
checksum: entry.checksum,
|
||||||
|
downloadUrl: entry.downloadUrl,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearManifestCache(): void {
|
||||||
|
cachedManifestEntries.clear();
|
||||||
|
clearLegacyManifestWarnings();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getManifestEntries(
|
async function getManifestEntries(
|
||||||
manifestUrl: string | undefined,
|
|
||||||
): Promise<ManifestEntry[]> {
|
|
||||||
let data: string;
|
|
||||||
if (manifestUrl !== undefined) {
|
|
||||||
core.info(`Fetching manifest-file from: ${manifestUrl}`);
|
|
||||||
const response = await fetch(manifestUrl, {});
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(
|
|
||||||
`Failed to fetch manifest-file: ${response.status} ${response.statusText}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
data = await response.text();
|
|
||||||
} else {
|
|
||||||
core.info("manifest-file not provided, reading from local file.");
|
|
||||||
const fileContent = await fs.readFile(localManifestFile);
|
|
||||||
data = fileContent.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return JSON.parse(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function updateVersionManifest(
|
|
||||||
manifestUrl: string,
|
manifestUrl: string,
|
||||||
downloadUrls: string[],
|
): Promise<ManifestEntry[]> {
|
||||||
): Promise<void> {
|
const cachedEntries = cachedManifestEntries.get(manifestUrl);
|
||||||
const manifest: ManifestEntry[] = [];
|
if (cachedEntries !== undefined) {
|
||||||
|
core.debug(`Using cached manifest-file from: ${manifestUrl}`);
|
||||||
for (const downloadUrl of downloadUrls) {
|
return cachedEntries;
|
||||||
const urlParts = downloadUrl.split("/");
|
}
|
||||||
const version = urlParts[urlParts.length - 2];
|
|
||||||
const artifactName = urlParts[urlParts.length - 1];
|
core.info(`Fetching manifest-file from: ${manifestUrl}`);
|
||||||
if (!artifactName.startsWith("uv-")) {
|
const response = await fetch(manifestUrl, {});
|
||||||
continue;
|
if (!response.ok) {
|
||||||
}
|
throw new Error(
|
||||||
if (artifactName.startsWith("uv-installer")) {
|
`Failed to fetch manifest-file: ${response.status} ${response.statusText}`,
|
||||||
continue;
|
);
|
||||||
}
|
}
|
||||||
const artifactParts = artifactName.split(".")[0].split("-");
|
|
||||||
manifest.push({
|
const data = await response.text();
|
||||||
arch: artifactParts[1],
|
const parsedEntries = parseManifestEntries(data, manifestUrl);
|
||||||
artifactName: artifactName,
|
cachedManifestEntries.set(manifestUrl, parsedEntries);
|
||||||
downloadUrl: downloadUrl,
|
|
||||||
platform: artifactName.split(`uv-${artifactParts[1]}-`)[1].split(".")[0],
|
return parsedEntries;
|
||||||
version: version,
|
}
|
||||||
});
|
|
||||||
|
function parseManifestEntries(
|
||||||
|
data: string,
|
||||||
|
manifestUrl: string,
|
||||||
|
): ManifestEntry[] {
|
||||||
|
const trimmed = data.trim();
|
||||||
|
if (trimmed === "") {
|
||||||
|
throw new Error(`manifest-file at ${manifestUrl} is empty.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedAsJson = tryParseJson(trimmed);
|
||||||
|
if (Array.isArray(parsedAsJson)) {
|
||||||
|
return parseLegacyManifestEntries(parsedAsJson, manifestUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
const versions = parseVersionData(trimmed, manifestUrl);
|
||||||
|
return mapNdjsonVersionsToManifestEntries(versions, manifestUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapNdjsonVersionsToManifestEntries(
|
||||||
|
versions: NdjsonVersion[],
|
||||||
|
manifestUrl: string,
|
||||||
|
): ManifestEntry[] {
|
||||||
|
const manifestEntries: ManifestEntry[] = [];
|
||||||
|
|
||||||
|
for (const versionData of versions) {
|
||||||
|
for (const artifact of versionData.artifacts) {
|
||||||
|
const [arch, ...platformParts] = artifact.platform.split("-");
|
||||||
|
if (arch === undefined || platformParts.length === 0) {
|
||||||
|
throw new Error(
|
||||||
|
`Invalid artifact platform '${artifact.platform}' in manifest-file ${manifestUrl}.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
manifestEntries.push({
|
||||||
|
arch,
|
||||||
|
archiveFormat: artifact.archive_format,
|
||||||
|
checksum: artifact.sha256,
|
||||||
|
downloadUrl: artifact.url,
|
||||||
|
platform: platformParts.join("-"),
|
||||||
|
variant: artifact.variant,
|
||||||
|
version: versionData.version,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return manifestEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectManifestEntry(
|
||||||
|
manifestEntries: ManifestEntry[],
|
||||||
|
manifestUrl: string,
|
||||||
|
version: string,
|
||||||
|
arch: string,
|
||||||
|
platform: string,
|
||||||
|
): ManifestEntry | undefined {
|
||||||
|
const matches = manifestEntries.filter(
|
||||||
|
(candidate) =>
|
||||||
|
candidate.version === version &&
|
||||||
|
candidate.arch === arch &&
|
||||||
|
candidate.platform === platform,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (matches.length === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectDefaultVariant(
|
||||||
|
matches,
|
||||||
|
`manifest-file ${manifestUrl} contains multiple artifacts for version ${version}, arch ${arch}, platform ${platform}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function tryParseJson(value: string): unknown {
|
||||||
|
try {
|
||||||
|
return JSON.parse(value);
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
core.debug(`Updating manifest-file: ${JSON.stringify(manifest)}`);
|
|
||||||
await fs.writeFile(manifestUrl, JSON.stringify(manifest));
|
|
||||||
}
|
}
|
||||||
|
|||||||
191
src/download/versions-client.ts
Normal file
191
src/download/versions-client.ts
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
import * as core from "@actions/core";
|
||||||
|
import { VERSIONS_NDJSON_URL } from "../utils/constants";
|
||||||
|
import { fetch } from "../utils/fetch";
|
||||||
|
import { selectDefaultVariant } from "./variant-selection";
|
||||||
|
|
||||||
|
export interface NdjsonArtifact {
|
||||||
|
platform: string;
|
||||||
|
variant?: string;
|
||||||
|
url: string;
|
||||||
|
archive_format: string;
|
||||||
|
sha256: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NdjsonVersion {
|
||||||
|
version: string;
|
||||||
|
artifacts: NdjsonArtifact[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ArtifactResult {
|
||||||
|
url: string;
|
||||||
|
sha256: string;
|
||||||
|
archiveFormat: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cachedVersionData = new Map<string, NdjsonVersion[]>();
|
||||||
|
|
||||||
|
export async function fetchVersionData(
|
||||||
|
url: string = VERSIONS_NDJSON_URL,
|
||||||
|
): Promise<NdjsonVersion[]> {
|
||||||
|
const cachedVersions = cachedVersionData.get(url);
|
||||||
|
if (cachedVersions !== undefined) {
|
||||||
|
core.debug(`Using cached NDJSON version data from ${url}`);
|
||||||
|
return cachedVersions;
|
||||||
|
}
|
||||||
|
|
||||||
|
core.info(`Fetching version data from ${url} ...`);
|
||||||
|
const response = await fetch(url, {});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to fetch version data: ${response.status} ${response.statusText}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = await response.text();
|
||||||
|
const versions = parseVersionData(body, url);
|
||||||
|
cachedVersionData.set(url, versions);
|
||||||
|
return versions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseVersionData(
|
||||||
|
data: string,
|
||||||
|
sourceDescription: string,
|
||||||
|
): NdjsonVersion[] {
|
||||||
|
const versions: NdjsonVersion[] = [];
|
||||||
|
|
||||||
|
for (const [index, line] of data.split("\n").entries()) {
|
||||||
|
const trimmed = line.trim();
|
||||||
|
if (trimmed === "") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let parsed: unknown;
|
||||||
|
try {
|
||||||
|
parsed = JSON.parse(trimmed);
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to parse version data from ${sourceDescription} at line ${index + 1}: ${(error as Error).message}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isNdjsonVersion(parsed)) {
|
||||||
|
throw new Error(
|
||||||
|
`Invalid NDJSON record in ${sourceDescription} at line ${index + 1}.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
versions.push(parsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (versions.length === 0) {
|
||||||
|
throw new Error(`No version data found in ${sourceDescription}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return versions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getLatestVersion(): Promise<string> {
|
||||||
|
const versions = await fetchVersionData();
|
||||||
|
const latestVersion = versions[0]?.version;
|
||||||
|
if (!latestVersion) {
|
||||||
|
throw new Error("No versions found in NDJSON data");
|
||||||
|
}
|
||||||
|
|
||||||
|
core.debug(`Latest version from NDJSON: ${latestVersion}`);
|
||||||
|
return latestVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getAllVersions(): Promise<string[]> {
|
||||||
|
const versions = await fetchVersionData();
|
||||||
|
return versions.map((versionData) => versionData.version);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getArtifact(
|
||||||
|
version: string,
|
||||||
|
arch: string,
|
||||||
|
platform: string,
|
||||||
|
): Promise<ArtifactResult | undefined> {
|
||||||
|
const versions = await fetchVersionData();
|
||||||
|
const versionData = versions.find(
|
||||||
|
(candidate) => candidate.version === version,
|
||||||
|
);
|
||||||
|
if (!versionData) {
|
||||||
|
core.debug(`Version ${version} not found in NDJSON data`);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetPlatform = `${arch}-${platform}`;
|
||||||
|
const matchingArtifacts = versionData.artifacts.filter(
|
||||||
|
(candidate) => candidate.platform === targetPlatform,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (matchingArtifacts.length === 0) {
|
||||||
|
core.debug(
|
||||||
|
`Artifact for ${targetPlatform} not found in version ${version}. Available platforms: ${versionData.artifacts
|
||||||
|
.map((candidate) => candidate.platform)
|
||||||
|
.join(", ")}`,
|
||||||
|
);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const artifact = selectArtifact(matchingArtifacts, version, targetPlatform);
|
||||||
|
|
||||||
|
return {
|
||||||
|
archiveFormat: artifact.archive_format,
|
||||||
|
sha256: artifact.sha256,
|
||||||
|
url: artifact.url,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearCache(url?: string): void {
|
||||||
|
if (url === undefined) {
|
||||||
|
cachedVersionData.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedVersionData.delete(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectArtifact(
|
||||||
|
artifacts: NdjsonArtifact[],
|
||||||
|
version: string,
|
||||||
|
targetPlatform: string,
|
||||||
|
): NdjsonArtifact {
|
||||||
|
return selectDefaultVariant(
|
||||||
|
artifacts,
|
||||||
|
`Multiple artifacts found for ${targetPlatform} in version ${version}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isNdjsonVersion(value: unknown): value is NdjsonVersion {
|
||||||
|
if (!isRecord(value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value.version !== "string" || !Array.isArray(value.artifacts)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.artifacts.every(isNdjsonArtifact);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isNdjsonArtifact(value: unknown): value is NdjsonArtifact {
|
||||||
|
if (!isRecord(value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const variantIsValid =
|
||||||
|
typeof value.variant === "string" || value.variant === undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
typeof value.archive_format === "string" &&
|
||||||
|
typeof value.platform === "string" &&
|
||||||
|
typeof value.sha256 === "string" &&
|
||||||
|
typeof value.url === "string" &&
|
||||||
|
variantIsValid
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||||
|
return typeof value === "object" && value !== null;
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import * as pep440 from "@renovatebot/pep440";
|
|||||||
import {
|
import {
|
||||||
STATE_CACHE_KEY,
|
STATE_CACHE_KEY,
|
||||||
STATE_CACHE_MATCHED_KEY,
|
STATE_CACHE_MATCHED_KEY,
|
||||||
|
STATE_PYTHON_CACHE_MATCHED_KEY,
|
||||||
} from "./cache/restore-cache";
|
} from "./cache/restore-cache";
|
||||||
import { STATE_UV_PATH, STATE_UV_VERSION } from "./utils/constants";
|
import { STATE_UV_PATH, STATE_UV_VERSION } from "./utils/constants";
|
||||||
import {
|
import {
|
||||||
@@ -26,6 +27,9 @@ export async function run(): Promise<void> {
|
|||||||
} else {
|
} else {
|
||||||
core.info("save-cache is false. Skipping save cache step.");
|
core.info("save-cache is false. Skipping save cache step.");
|
||||||
}
|
}
|
||||||
|
// https://github.com/nodejs/node/issues/56645#issuecomment-3077594952
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||||
|
|
||||||
// node will stay alive if any promises are not resolved,
|
// node will stay alive if any promises are not resolved,
|
||||||
// which is a possibility if HTTP requests are dangling
|
// which is a possibility if HTTP requests are dangling
|
||||||
// due to retries or timeouts. We know that if we got here
|
// due to retries or timeouts. We know that if we got here
|
||||||
@@ -49,56 +53,48 @@ async function saveCache(): Promise<void> {
|
|||||||
}
|
}
|
||||||
if (matchedKey === cacheKey) {
|
if (matchedKey === cacheKey) {
|
||||||
core.info(`Cache hit occurred on key ${cacheKey}, not saving cache.`);
|
core.info(`Cache hit occurred on key ${cacheKey}, not saving cache.`);
|
||||||
return;
|
} else {
|
||||||
}
|
if (shouldPruneCache) {
|
||||||
|
await pruneCache();
|
||||||
if (shouldPruneCache) {
|
|
||||||
await pruneCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
let actualCachePath = cacheLocalPath;
|
|
||||||
if (process.env.UV_CACHE_DIR && process.env.UV_CACHE_DIR !== cacheLocalPath) {
|
|
||||||
core.warning(
|
|
||||||
`The environment variable UV_CACHE_DIR has been changed to "${process.env.UV_CACHE_DIR}", by an action or step running after astral-sh/setup-uv. This can lead to unexpected behavior. If you expected this to happen set the cache-local-path input to "${process.env.UV_CACHE_DIR}" instead of "${cacheLocalPath}".`,
|
|
||||||
);
|
|
||||||
actualCachePath = process.env.UV_CACHE_DIR;
|
|
||||||
}
|
|
||||||
|
|
||||||
core.info(`Saving cache path: ${actualCachePath}`);
|
|
||||||
if (!fs.existsSync(actualCachePath) && !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 (cachePython) {
|
|
||||||
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(", ")}`);
|
const actualCachePath = getUvCachePath();
|
||||||
try {
|
if (!fs.existsSync(actualCachePath)) {
|
||||||
await cache.saveCache(cachePaths, cacheKey);
|
if (ignoreNothingToCache) {
|
||||||
core.info(`cache saved with the key: ${cacheKey}`);
|
core.info(
|
||||||
} catch (e) {
|
"No cacheable uv cache paths were found. Ignoring because ignore-nothing-to-cache is enabled.",
|
||||||
if (
|
);
|
||||||
e instanceof Error &&
|
} else {
|
||||||
e.message ===
|
throw new Error(
|
||||||
"Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved."
|
`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.`,
|
||||||
) {
|
);
|
||||||
core.info(
|
}
|
||||||
"No cacheable paths were found. Ignoring because ignore-nothing-to-save is enabled.",
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
throw e;
|
await saveCacheToKey(
|
||||||
|
cacheKey,
|
||||||
|
actualCachePath,
|
||||||
|
STATE_CACHE_MATCHED_KEY,
|
||||||
|
"uv cache",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cachePython) {
|
||||||
|
if (!fs.existsSync(pythonDir)) {
|
||||||
|
core.warning(
|
||||||
|
`Python cache path ${pythonDir} does not exist on disk. Skipping Python cache save because no managed Python installation was found. If you want uv to install managed Python instead of using a system interpreter, set UV_PYTHON_PREFERENCE=only-managed.`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pythonCacheKey = `${cacheKey}-python`;
|
||||||
|
await saveCacheToKey(
|
||||||
|
pythonCacheKey,
|
||||||
|
pythonDir,
|
||||||
|
STATE_PYTHON_CACHE_MATCHED_KEY,
|
||||||
|
"Python cache",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function pruneCache(): Promise<void> {
|
async function pruneCache(): Promise<void> {
|
||||||
@@ -117,4 +113,42 @@ async function pruneCache(): Promise<void> {
|
|||||||
await exec.exec(uvPath, execArgs, options);
|
await exec.exec(uvPath, execArgs, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getUvCachePath(): string {
|
||||||
|
if (cacheLocalPath === undefined) {
|
||||||
|
throw new Error(
|
||||||
|
"cache-local-path is not set. Cannot save cache without a valid cache path.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
process.env.UV_CACHE_DIR &&
|
||||||
|
process.env.UV_CACHE_DIR !== cacheLocalPath.path
|
||||||
|
) {
|
||||||
|
core.warning(
|
||||||
|
`The environment variable UV_CACHE_DIR has been changed to "${process.env.UV_CACHE_DIR}", by an action or step running after astral-sh/setup-uv. This can lead to unexpected behavior. If you expected this to happen set the cache-local-path input to "${process.env.UV_CACHE_DIR}" instead of "${cacheLocalPath.path}".`,
|
||||||
|
);
|
||||||
|
return process.env.UV_CACHE_DIR;
|
||||||
|
}
|
||||||
|
return cacheLocalPath.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveCacheToKey(
|
||||||
|
cacheKey: string,
|
||||||
|
cachePath: string,
|
||||||
|
stateKey: string,
|
||||||
|
cacheName: string,
|
||||||
|
): Promise<void> {
|
||||||
|
const matchedKey = core.getState(stateKey);
|
||||||
|
|
||||||
|
if (matchedKey === cacheKey) {
|
||||||
|
core.info(
|
||||||
|
`${cacheName} hit occurred on key ${cacheKey}, not saving cache.`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
core.info(`Including ${cacheName} path: ${cachePath}`);
|
||||||
|
await cache.saveCache([cachePath], cacheKey);
|
||||||
|
core.info(`${cacheName} saved with key: ${cacheKey}`);
|
||||||
|
}
|
||||||
|
|
||||||
run();
|
run();
|
||||||
|
|||||||
@@ -5,14 +5,15 @@ import * as exec from "@actions/exec";
|
|||||||
import { restoreCache } from "./cache/restore-cache";
|
import { restoreCache } from "./cache/restore-cache";
|
||||||
import {
|
import {
|
||||||
downloadVersionFromManifest,
|
downloadVersionFromManifest,
|
||||||
|
downloadVersionFromNdjson,
|
||||||
resolveVersion,
|
resolveVersion,
|
||||||
tryGetFromToolCache,
|
tryGetFromToolCache,
|
||||||
} from "./download/download-version";
|
} from "./download/download-version";
|
||||||
import { getConfigValueFromTomlFile } from "./utils/config-file";
|
|
||||||
import { STATE_UV_PATH, STATE_UV_VERSION } from "./utils/constants";
|
import { STATE_UV_PATH, STATE_UV_VERSION } from "./utils/constants";
|
||||||
import {
|
import {
|
||||||
activateEnvironment as activateEnvironmentInput,
|
activateEnvironment as activateEnvironmentInput,
|
||||||
addProblemMatchers,
|
addProblemMatchers,
|
||||||
|
CacheLocalSource,
|
||||||
cacheLocalPath,
|
cacheLocalPath,
|
||||||
checkSum,
|
checkSum,
|
||||||
enableCache,
|
enableCache,
|
||||||
@@ -24,6 +25,7 @@ import {
|
|||||||
resolutionStrategy,
|
resolutionStrategy,
|
||||||
toolBinDir,
|
toolBinDir,
|
||||||
toolDir,
|
toolDir,
|
||||||
|
venvPath,
|
||||||
versionFile as versionFileInput,
|
versionFile as versionFileInput,
|
||||||
version as versionInput,
|
version as versionInput,
|
||||||
workingDirectory,
|
workingDirectory,
|
||||||
@@ -36,6 +38,37 @@ import {
|
|||||||
} from "./utils/platforms";
|
} from "./utils/platforms";
|
||||||
import { getUvVersionFromFile } from "./version/resolve";
|
import { getUvVersionFromFile } from "./version/resolve";
|
||||||
|
|
||||||
|
async function getPythonVersion(): Promise<string> {
|
||||||
|
if (pythonVersion !== "") {
|
||||||
|
return pythonVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = "";
|
||||||
|
const options: exec.ExecOptions = {
|
||||||
|
listeners: {
|
||||||
|
stdout: (data: Buffer) => {
|
||||||
|
output += data.toString();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
silent: !core.isDebug(),
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const execArgs = ["python", "find", "--directory", workingDirectory];
|
||||||
|
await exec.exec("uv", execArgs, options);
|
||||||
|
const pythonPath = output.trim();
|
||||||
|
|
||||||
|
output = "";
|
||||||
|
await exec.exec(pythonPath, ["--version"], options);
|
||||||
|
// output is like "Python 3.8.10"
|
||||||
|
return output.split(" ")[1].trim();
|
||||||
|
} catch (error) {
|
||||||
|
const err = error as Error;
|
||||||
|
core.debug(`Failed to get python version from uv. Error: ${err.message}`);
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
detectEmptyWorkdir();
|
detectEmptyWorkdir();
|
||||||
const platform = await getPlatform();
|
const platform = await getPlatform();
|
||||||
@@ -63,9 +96,14 @@ async function run(): Promise<void> {
|
|||||||
core.saveState(STATE_UV_VERSION, setupResult.version);
|
core.saveState(STATE_UV_VERSION, setupResult.version);
|
||||||
core.info(`Successfully installed uv version ${setupResult.version}`);
|
core.info(`Successfully installed uv version ${setupResult.version}`);
|
||||||
|
|
||||||
|
const pythonVersion = await getPythonVersion();
|
||||||
|
core.setOutput("python-version", pythonVersion);
|
||||||
|
|
||||||
if (enableCache) {
|
if (enableCache) {
|
||||||
await restoreCache();
|
await restoreCache(pythonVersion);
|
||||||
}
|
}
|
||||||
|
// https://github.com/nodejs/node/issues/56645#issuecomment-3077594952
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
core.setFailed((err as Error).message);
|
core.setFailed((err as Error).message);
|
||||||
@@ -102,14 +140,23 @@ async function setupUv(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const downloadVersionResult = await downloadVersionFromManifest(
|
const downloadVersionResult =
|
||||||
manifestFile,
|
manifestFile !== undefined
|
||||||
platform,
|
? await downloadVersionFromManifest(
|
||||||
arch,
|
manifestFile,
|
||||||
resolvedVersion,
|
platform,
|
||||||
checkSum,
|
arch,
|
||||||
githubToken,
|
resolvedVersion,
|
||||||
);
|
checkSum,
|
||||||
|
githubToken,
|
||||||
|
)
|
||||||
|
: await downloadVersionFromNdjson(
|
||||||
|
platform,
|
||||||
|
arch,
|
||||||
|
resolvedVersion,
|
||||||
|
checkSum,
|
||||||
|
githubToken,
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
uvDir: downloadVersionResult.cachedToolDir,
|
uvDir: downloadVersionResult.cachedToolDir,
|
||||||
@@ -121,12 +168,7 @@ async function determineVersion(
|
|||||||
manifestFile: string | undefined,
|
manifestFile: string | undefined,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
if (versionInput !== "") {
|
if (versionInput !== "") {
|
||||||
return await resolveVersion(
|
return await resolveVersion(versionInput, manifestFile, resolutionStrategy);
|
||||||
versionInput,
|
|
||||||
manifestFile,
|
|
||||||
githubToken,
|
|
||||||
resolutionStrategy,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (versionFileInput !== "") {
|
if (versionFileInput !== "") {
|
||||||
const versionFromFile = getUvVersionFromFile(versionFileInput);
|
const versionFromFile = getUvVersionFromFile(versionFileInput);
|
||||||
@@ -138,7 +180,6 @@ async function determineVersion(
|
|||||||
return await resolveVersion(
|
return await resolveVersion(
|
||||||
versionFromFile,
|
versionFromFile,
|
||||||
manifestFile,
|
manifestFile,
|
||||||
githubToken,
|
|
||||||
resolutionStrategy,
|
resolutionStrategy,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -156,7 +197,6 @@ async function determineVersion(
|
|||||||
return await resolveVersion(
|
return await resolveVersion(
|
||||||
versionFromUvToml || versionFromPyproject || "latest",
|
versionFromUvToml || versionFromPyproject || "latest",
|
||||||
manifestFile,
|
manifestFile,
|
||||||
githubToken,
|
|
||||||
resolutionStrategy,
|
resolutionStrategy,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -233,12 +273,16 @@ async function activateEnvironment(): Promise<void> {
|
|||||||
"UV_NO_MODIFY_PATH and activate-environment cannot be used together.",
|
"UV_NO_MODIFY_PATH and activate-environment cannot be used together.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const execArgs = ["venv", ".venv", "--directory", workingDirectory];
|
|
||||||
|
|
||||||
core.info("Activating python venv...");
|
core.info(`Creating and activating python venv at ${venvPath}...`);
|
||||||
await exec.exec("uv", execArgs);
|
await exec.exec("uv", [
|
||||||
|
"venv",
|
||||||
|
venvPath,
|
||||||
|
"--directory",
|
||||||
|
workingDirectory,
|
||||||
|
"--clear",
|
||||||
|
]);
|
||||||
|
|
||||||
const venvPath = path.resolve(`${workingDirectory}${path.sep}.venv`);
|
|
||||||
let venvBinPath = `${venvPath}${path.sep}bin`;
|
let venvBinPath = `${venvPath}${path.sep}bin`;
|
||||||
if (process.platform === "win32") {
|
if (process.platform === "win32") {
|
||||||
venvBinPath = `${venvPath}${path.sep}Scripts`;
|
venvBinPath = `${venvPath}${path.sep}Scripts`;
|
||||||
@@ -250,16 +294,15 @@ async function activateEnvironment(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setCacheDir(): void {
|
function setCacheDir(): void {
|
||||||
if (enableCache) {
|
if (cacheLocalPath !== undefined) {
|
||||||
const cacheDirFromConfig = getConfigValueFromTomlFile("", "cache-dir");
|
if (cacheLocalPath.source === CacheLocalSource.Config) {
|
||||||
if (cacheDirFromConfig !== undefined) {
|
|
||||||
core.info(
|
core.info(
|
||||||
"Using cache-dir from uv config file, not modifying UV_CACHE_DIR",
|
"Using cache-dir from uv config file, not modifying UV_CACHE_DIR",
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
core.exportVariable("UV_CACHE_DIR", cacheLocalPath);
|
core.exportVariable("UV_CACHE_DIR", cacheLocalPath.path);
|
||||||
core.info(`Set UV_CACHE_DIR to ${cacheLocalPath}`);
|
core.info(`Set UV_CACHE_DIR to ${cacheLocalPath.path}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
81
src/update-known-checksums.ts
Normal file
81
src/update-known-checksums.ts
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import * as core from "@actions/core";
|
||||||
|
import * as semver from "semver";
|
||||||
|
import { KNOWN_CHECKSUMS } from "./download/checksum/known-checksums";
|
||||||
|
import {
|
||||||
|
type ChecksumEntry,
|
||||||
|
updateChecksums,
|
||||||
|
} from "./download/checksum/update-known-checksums";
|
||||||
|
import {
|
||||||
|
fetchVersionData,
|
||||||
|
getLatestVersion,
|
||||||
|
type NdjsonVersion,
|
||||||
|
} from "./download/versions-client";
|
||||||
|
|
||||||
|
const VERSION_IN_CHECKSUM_KEY_PATTERN =
|
||||||
|
/-(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)$/;
|
||||||
|
|
||||||
|
async function run(): Promise<void> {
|
||||||
|
const checksumFilePath = process.argv.slice(2)[0];
|
||||||
|
if (!checksumFilePath) {
|
||||||
|
throw new Error(
|
||||||
|
"Missing checksum file path. Usage: node dist/update-known-checksums/index.js <checksum-file-path>",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const latestVersion = await getLatestVersion();
|
||||||
|
const latestKnownVersion = getLatestKnownVersionFromChecksums();
|
||||||
|
|
||||||
|
if (semver.lte(latestVersion, latestKnownVersion)) {
|
||||||
|
core.info(
|
||||||
|
`Latest release (${latestVersion}) is not newer than the latest known version (${latestKnownVersion}). Skipping update.`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const versions = await fetchVersionData();
|
||||||
|
const checksumEntries = extractChecksumsFromNdjson(versions);
|
||||||
|
await updateChecksums(checksumFilePath, checksumEntries);
|
||||||
|
|
||||||
|
core.setOutput("latest-version", latestVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLatestKnownVersionFromChecksums(): string {
|
||||||
|
const versions = new Set<string>();
|
||||||
|
|
||||||
|
for (const key of Object.keys(KNOWN_CHECKSUMS)) {
|
||||||
|
const version = extractVersionFromChecksumKey(key);
|
||||||
|
if (version !== undefined) {
|
||||||
|
versions.add(version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const latestVersion = [...versions].sort(semver.rcompare)[0];
|
||||||
|
if (!latestVersion) {
|
||||||
|
throw new Error("Could not determine latest known version from checksums.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return latestVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractVersionFromChecksumKey(key: string): string | undefined {
|
||||||
|
return key.match(VERSION_IN_CHECKSUM_KEY_PATTERN)?.[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractChecksumsFromNdjson(
|
||||||
|
versions: NdjsonVersion[],
|
||||||
|
): ChecksumEntry[] {
|
||||||
|
const checksums: ChecksumEntry[] = [];
|
||||||
|
|
||||||
|
for (const version of versions) {
|
||||||
|
for (const artifact of version.artifacts) {
|
||||||
|
checksums.push({
|
||||||
|
checksum: artifact.sha256,
|
||||||
|
key: `${artifact.platform}-${version.version}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return checksums;
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
import * as core from "@actions/core";
|
|
||||||
import type { Endpoints } from "@octokit/types";
|
|
||||||
import * as semver from "semver";
|
|
||||||
import { updateChecksums } from "./download/checksum/update-known-checksums";
|
|
||||||
import {
|
|
||||||
getLatestKnownVersion,
|
|
||||||
updateVersionManifest,
|
|
||||||
} from "./download/version-manifest";
|
|
||||||
import { OWNER, REPO } from "./utils/constants";
|
|
||||||
import { Octokit } from "./utils/octokit";
|
|
||||||
|
|
||||||
type Release =
|
|
||||||
Endpoints["GET /repos/{owner}/{repo}/releases"]["response"]["data"][number];
|
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
|
||||||
const checksumFilePath = process.argv.slice(2)[0];
|
|
||||||
const versionsManifestFile = process.argv.slice(2)[1];
|
|
||||||
const githubToken = process.argv.slice(2)[2];
|
|
||||||
|
|
||||||
const octokit = new Octokit({
|
|
||||||
auth: githubToken,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { data: latestRelease } = await octokit.rest.repos.getLatestRelease({
|
|
||||||
owner: OWNER,
|
|
||||||
repo: REPO,
|
|
||||||
});
|
|
||||||
|
|
||||||
const latestKnownVersion = await getLatestKnownVersion(undefined);
|
|
||||||
|
|
||||||
if (semver.lte(latestRelease.tag_name, latestKnownVersion)) {
|
|
||||||
core.info(
|
|
||||||
`Latest release (${latestRelease.tag_name}) is not newer than the latest known version (${latestKnownVersion}). Skipping update.`,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const releases: Release[] = await octokit.paginate(
|
|
||||||
octokit.rest.repos.listReleases,
|
|
||||||
{
|
|
||||||
owner: OWNER,
|
|
||||||
repo: REPO,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
const checksumDownloadUrls: string[] = releases.flatMap((release) =>
|
|
||||||
release.assets
|
|
||||||
.filter((asset) => asset.name.endsWith(".sha256"))
|
|
||||||
.map((asset) => asset.browser_download_url),
|
|
||||||
);
|
|
||||||
await updateChecksums(checksumFilePath, checksumDownloadUrls);
|
|
||||||
|
|
||||||
const artifactDownloadUrls: string[] = releases.flatMap((release) =>
|
|
||||||
release.assets
|
|
||||||
.filter((asset) => !asset.name.endsWith(".sha256"))
|
|
||||||
.map((asset) => asset.browser_download_url),
|
|
||||||
);
|
|
||||||
|
|
||||||
await updateVersionManifest(versionsManifestFile, artifactDownloadUrls);
|
|
||||||
|
|
||||||
core.setOutput("latest-version", latestRelease.tag_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
run();
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
export const REPO = "uv";
|
|
||||||
export const OWNER = "astral-sh";
|
|
||||||
export const TOOL_CACHE_NAME = "uv";
|
export const TOOL_CACHE_NAME = "uv";
|
||||||
export const STATE_UV_PATH = "uv-path";
|
export const STATE_UV_PATH = "uv-path";
|
||||||
export const STATE_UV_VERSION = "uv-version";
|
export const STATE_UV_VERSION = "uv-version";
|
||||||
|
export const VERSIONS_NDJSON_URL =
|
||||||
|
"https://raw.githubusercontent.com/astral-sh/versions/main/v1/uv.ndjson";
|
||||||
|
|||||||
@@ -2,11 +2,19 @@ import path from "node:path";
|
|||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
import { getConfigValueFromTomlFile } from "./config-file";
|
import { getConfigValueFromTomlFile } from "./config-file";
|
||||||
|
|
||||||
|
export enum CacheLocalSource {
|
||||||
|
Input,
|
||||||
|
Config,
|
||||||
|
Env,
|
||||||
|
Default,
|
||||||
|
}
|
||||||
|
|
||||||
export const workingDirectory = core.getInput("working-directory");
|
export const workingDirectory = core.getInput("working-directory");
|
||||||
export const version = core.getInput("version");
|
export const version = core.getInput("version");
|
||||||
export const versionFile = getVersionFile();
|
export const versionFile = getVersionFile();
|
||||||
export const pythonVersion = core.getInput("python-version");
|
export const pythonVersion = core.getInput("python-version");
|
||||||
export const activateEnvironment = core.getBooleanInput("activate-environment");
|
export const activateEnvironment = core.getBooleanInput("activate-environment");
|
||||||
|
export const venvPath = getVenvPath();
|
||||||
export const checkSum = core.getInput("checksum");
|
export const checkSum = core.getInput("checksum");
|
||||||
export const enableCache = getEnableCache();
|
export const enableCache = getEnableCache();
|
||||||
export const restoreCache = core.getInput("restore-cache") === "true";
|
export const restoreCache = core.getInput("restore-cache") === "true";
|
||||||
@@ -38,6 +46,18 @@ function getVersionFile(): string {
|
|||||||
return versionFileInput;
|
return versionFileInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getVenvPath(): string {
|
||||||
|
const venvPathInput = core.getInput("venv-path");
|
||||||
|
if (venvPathInput !== "") {
|
||||||
|
if (!activateEnvironment) {
|
||||||
|
core.warning("venv-path is only used when activate-environment is true");
|
||||||
|
}
|
||||||
|
const tildeExpanded = expandTilde(venvPathInput);
|
||||||
|
return normalizePath(resolveRelativePath(tildeExpanded));
|
||||||
|
}
|
||||||
|
return normalizePath(resolveRelativePath(".venv"));
|
||||||
|
}
|
||||||
|
|
||||||
function getEnableCache(): boolean {
|
function getEnableCache(): boolean {
|
||||||
const enableCacheInput = core.getInput("enable-cache");
|
const enableCacheInput = core.getInput("enable-cache");
|
||||||
if (enableCacheInput === "auto") {
|
if (enableCacheInput === "auto") {
|
||||||
@@ -80,32 +100,51 @@ function getToolDir(): string | undefined {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCacheLocalPath(): string {
|
function getCacheLocalPath():
|
||||||
|
| {
|
||||||
|
path: string;
|
||||||
|
source: CacheLocalSource;
|
||||||
|
}
|
||||||
|
| undefined {
|
||||||
const cacheLocalPathInput = core.getInput("cache-local-path");
|
const cacheLocalPathInput = core.getInput("cache-local-path");
|
||||||
if (cacheLocalPathInput !== "") {
|
if (cacheLocalPathInput !== "") {
|
||||||
const tildeExpanded = expandTilde(cacheLocalPathInput);
|
const tildeExpanded = expandTilde(cacheLocalPathInput);
|
||||||
return resolveRelativePath(tildeExpanded);
|
return {
|
||||||
|
path: resolveRelativePath(tildeExpanded),
|
||||||
|
source: CacheLocalSource.Input,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
const cacheDirFromConfig = getCacheDirFromConfig();
|
const cacheDirFromConfig = getCacheDirFromConfig();
|
||||||
if (cacheDirFromConfig !== undefined) {
|
if (cacheDirFromConfig !== undefined) {
|
||||||
return cacheDirFromConfig;
|
return { path: cacheDirFromConfig, source: CacheLocalSource.Config };
|
||||||
}
|
}
|
||||||
if (process.env.UV_CACHE_DIR !== undefined) {
|
if (process.env.UV_CACHE_DIR !== undefined) {
|
||||||
core.info(`UV_CACHE_DIR is already set to ${process.env.UV_CACHE_DIR}`);
|
core.info(`UV_CACHE_DIR is already set to ${process.env.UV_CACHE_DIR}`);
|
||||||
return process.env.UV_CACHE_DIR;
|
return { path: process.env.UV_CACHE_DIR, source: CacheLocalSource.Env };
|
||||||
}
|
}
|
||||||
if (process.env.RUNNER_ENVIRONMENT === "github-hosted") {
|
if (getEnableCache()) {
|
||||||
if (process.env.RUNNER_TEMP !== undefined) {
|
if (process.env.RUNNER_ENVIRONMENT === "github-hosted") {
|
||||||
return `${process.env.RUNNER_TEMP}${path.sep}setup-uv-cache`;
|
if (process.env.RUNNER_TEMP !== undefined) {
|
||||||
|
return {
|
||||||
|
path: `${process.env.RUNNER_TEMP}${path.sep}setup-uv-cache`,
|
||||||
|
source: CacheLocalSource.Default,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
throw Error(
|
||||||
|
"Could not determine UV_CACHE_DIR. Please make sure RUNNER_TEMP is set or provide the cache-local-path input",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
throw Error(
|
if (process.platform === "win32") {
|
||||||
"Could not determine UV_CACHE_DIR. Please make sure RUNNER_TEMP is set or provide the cache-local-path input",
|
return {
|
||||||
);
|
path: `${process.env.APPDATA}${path.sep}uv${path.sep}cache`,
|
||||||
|
source: CacheLocalSource.Default,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
path: `${process.env.HOME}${path.sep}.cache${path.sep}uv`,
|
||||||
|
source: CacheLocalSource.Default,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (process.platform === "win32") {
|
|
||||||
return `${process.env.APPDATA}${path.sep}uv${path.sep}cache`;
|
|
||||||
}
|
|
||||||
return `${process.env.HOME}${path.sep}.cache${path.sep}uv`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCacheDirFromConfig(): string | undefined {
|
function getCacheDirFromConfig(): string | undefined {
|
||||||
@@ -129,7 +168,7 @@ function getCacheDirFromConfig(): string | undefined {
|
|||||||
export function getUvPythonDir(): string {
|
export function getUvPythonDir(): string {
|
||||||
if (process.env.UV_PYTHON_INSTALL_DIR !== undefined) {
|
if (process.env.UV_PYTHON_INSTALL_DIR !== undefined) {
|
||||||
core.info(
|
core.info(
|
||||||
`UV_PYTHON_INSTALL_DIR is already set to ${process.env.UV_PYTHON_INSTALL_DIR}`,
|
`UV_PYTHON_INSTALL_DIR is already set to ${process.env.UV_PYTHON_INSTALL_DIR}`,
|
||||||
);
|
);
|
||||||
return process.env.UV_PYTHON_INSTALL_DIR;
|
return process.env.UV_PYTHON_INSTALL_DIR;
|
||||||
}
|
}
|
||||||
@@ -168,6 +207,19 @@ function expandTilde(input: string): string {
|
|||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizePath(inputPath: string): string {
|
||||||
|
const normalized = path.normalize(inputPath);
|
||||||
|
const root = path.parse(normalized).root;
|
||||||
|
|
||||||
|
// Remove any trailing path separators, except when the whole path is the root.
|
||||||
|
let trimmed = normalized;
|
||||||
|
while (trimmed.length > root.length && trimmed.endsWith(path.sep)) {
|
||||||
|
trimmed = trimmed.slice(0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return trimmed;
|
||||||
|
}
|
||||||
|
|
||||||
function resolveRelativePath(inputPath: string): string {
|
function resolveRelativePath(inputPath: string): string {
|
||||||
const hasNegation = inputPath.startsWith("!");
|
const hasNegation = inputPath.startsWith("!");
|
||||||
const pathWithoutNegation = hasNegation ? inputPath.substring(1) : inputPath;
|
const pathWithoutNegation = hasNegation ? inputPath.substring(1) : inputPath;
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
import type { OctokitOptions } from "@octokit/core";
|
|
||||||
import { Octokit as Core } from "@octokit/core";
|
|
||||||
import {
|
|
||||||
type PaginateInterface,
|
|
||||||
paginateRest,
|
|
||||||
} from "@octokit/plugin-paginate-rest";
|
|
||||||
import { legacyRestEndpointMethods } from "@octokit/plugin-rest-endpoint-methods";
|
|
||||||
import { fetch as customFetch } from "./fetch";
|
|
||||||
|
|
||||||
export type { RestEndpointMethodTypes } from "@octokit/plugin-rest-endpoint-methods";
|
|
||||||
|
|
||||||
const DEFAULTS = {
|
|
||||||
baseUrl: "https://api.github.com",
|
|
||||||
userAgent: "setup-uv",
|
|
||||||
};
|
|
||||||
|
|
||||||
const OctokitWithPlugins = Core.plugin(paginateRest, legacyRestEndpointMethods);
|
|
||||||
|
|
||||||
export const Octokit = OctokitWithPlugins.defaults(function buildDefaults(
|
|
||||||
options: OctokitOptions,
|
|
||||||
): OctokitOptions {
|
|
||||||
return {
|
|
||||||
...DEFAULTS,
|
|
||||||
...options,
|
|
||||||
request: {
|
|
||||||
fetch: customFetch,
|
|
||||||
...options.request,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
export type Octokit = InstanceType<typeof OctokitWithPlugins> & {
|
|
||||||
paginate: PaginateInterface;
|
|
||||||
};
|
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import fs from "node:fs";
|
||||||
|
import os from "node:os";
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
import * as exec from "@actions/exec";
|
import * as exec from "@actions/exec";
|
||||||
export type Platform =
|
export type Platform =
|
||||||
@@ -11,6 +13,7 @@ export type Architecture =
|
|||||||
| "x86_64"
|
| "x86_64"
|
||||||
| "aarch64"
|
| "aarch64"
|
||||||
| "s390x"
|
| "s390x"
|
||||||
|
| "riscv64gc"
|
||||||
| "powerpc64le";
|
| "powerpc64le";
|
||||||
|
|
||||||
export function getArch(): Architecture | undefined {
|
export function getArch(): Architecture | undefined {
|
||||||
@@ -19,6 +22,7 @@ export function getArch(): Architecture | undefined {
|
|||||||
arm64: "aarch64",
|
arm64: "aarch64",
|
||||||
ia32: "i686",
|
ia32: "i686",
|
||||||
ppc64: "powerpc64le",
|
ppc64: "powerpc64le",
|
||||||
|
riscv64: "riscv64gc",
|
||||||
s390x: "s390x",
|
s390x: "s390x",
|
||||||
x64: "x86_64",
|
x64: "x86_64",
|
||||||
};
|
};
|
||||||
@@ -74,3 +78,77 @@ async function isMuslOs(): Promise<boolean> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns OS name and version for cache key differentiation.
|
||||||
|
* Examples: "ubuntu-22.04", "macos-14", "windows-2022"
|
||||||
|
* Throws if OS detection fails.
|
||||||
|
*/
|
||||||
|
export function getOSNameVersion(): string {
|
||||||
|
const platform = process.platform;
|
||||||
|
|
||||||
|
if (platform === "linux") {
|
||||||
|
return getLinuxOSNameVersion();
|
||||||
|
}
|
||||||
|
if (platform === "darwin") {
|
||||||
|
return getMacOSNameVersion();
|
||||||
|
}
|
||||||
|
if (platform === "win32") {
|
||||||
|
return getWindowsNameVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`Unsupported platform: ${platform}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLinuxOSNameVersion(): string {
|
||||||
|
const files = ["/etc/os-release", "/usr/lib/os-release"];
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
try {
|
||||||
|
const content = fs.readFileSync(file, "utf8");
|
||||||
|
const id = parseOsReleaseValue(content, "ID");
|
||||||
|
const versionId = parseOsReleaseValue(content, "VERSION_ID");
|
||||||
|
// Fallback for rolling releases (debian:unstable/testing, arch, etc.)
|
||||||
|
// that don't have VERSION_ID but have VERSION_CODENAME
|
||||||
|
const versionCodename = parseOsReleaseValue(content, "VERSION_CODENAME");
|
||||||
|
|
||||||
|
if (id && versionId) {
|
||||||
|
return `${id}-${versionId}`;
|
||||||
|
}
|
||||||
|
if (id && versionCodename) {
|
||||||
|
return `${id}-${versionCodename}`;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Try next file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
"Failed to determine Linux distribution. " +
|
||||||
|
"Could not read /etc/os-release or /usr/lib/os-release",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseOsReleaseValue(content: string, key: string): string | undefined {
|
||||||
|
const regex = new RegExp(`^${key}=["']?([^"'\\n]*)["']?$`, "m");
|
||||||
|
const match = content.match(regex);
|
||||||
|
return match?.[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMacOSNameVersion(): string {
|
||||||
|
const darwinVersion = Number.parseInt(os.release().split(".")[0], 10);
|
||||||
|
if (Number.isNaN(darwinVersion)) {
|
||||||
|
throw new Error(`Failed to parse macOS version from: ${os.release()}`);
|
||||||
|
}
|
||||||
|
const macosVersion = darwinVersion - 9;
|
||||||
|
return `macos-${macosVersion}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWindowsNameVersion(): string {
|
||||||
|
const version = os.version();
|
||||||
|
const match = version.match(/Windows(?: Server)? (\d+)/);
|
||||||
|
if (!match) {
|
||||||
|
throw new Error(`Failed to parse Windows version from: ${version}`);
|
||||||
|
}
|
||||||
|
return `windows-${match[1]}`;
|
||||||
|
}
|
||||||
|
|||||||
27036
version-manifest.json
27036
version-manifest.json
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user