Compare commits

...

32 Commits
v2 ... main

Author SHA1 Message Date
Matteo Castellini
94a823180e
Update @actions/cache to v4.0.3 (#71) 2025-04-23 15:44:04 +08:00
Firas Cheaib
deb8d8a4e2
fix: use correct libgcc for arm64 (#68)
Signed-off-by: Firas Cheaib <firascheaib@gmail.com>
2025-03-06 08:40:24 +08:00
Frost Ming
b2472ca425
fix: set python version first (#65)
* fix: set python version first

Signed-off-by: Frost Ming <me@frostming.com>

* fix: drop 3.8 and add 3.13

Signed-off-by: Frost Ming <me@frostming.com>

* fix: update pdm.lock

Signed-off-by: Frost Ming <me@frostming.com>
2024-11-28 09:15:12 +08:00
Szymon Maszke
2f3a9be7ac
feat: add ability to restore cache by exact match (#60)
Signed-off-by: szymonmaszke <github@maszke.co>
2024-08-09 15:07:36 +08:00
❤是纱雾酱哟~
176c044a20
feat(cache): Distinguish architectures of caches (#58)
Signed-off-by: ❤是纱雾酱哟~ <49941141+Dragon1573@users.noreply.github.com>
2024-07-03 08:48:56 +08:00
Kenji Matsuoka
568ddd6940
fix: move process.exit() to cache-save.ts (#53) 2024-04-18 15:41:39 +08:00
Kenji Matsuoka
7d10bd0f83
feat: Explicitly exit the process to not wait for hanging promises (#51)
* Explicitly exit the process to not wait for hanging promises

As with other actions like setup-node, I'm seeing 2-4 minute delays in post cache actions lately. Apparently this is because of a change in node behavior: https://github.com/ruby/setup-ruby/issues/543#issuecomment-1793608370

The fix, as with other actions, is to explicitly exit so as not to wait for hanging promises.

* transpiled
2024-03-22 10:41:40 +08:00
Florian Polster
327261f959
doc: Update 'Why do I need this action?' section of README (#49)
* Update 'Why do I need this action?' section of README

* Update README.md
2024-02-01 14:52:39 +08:00
Frost Ming
c050bdcb24
doc: update readme
Signed-off-by: Frost Ming <me@frostming.com>
2024-01-25 19:31:08 +08:00
Frost Ming
d4d1a77594
fix: version resolution when only version file is present
Signed-off-by: Frost Ming <me@frostming.com>
2024-01-25 19:30:00 +08:00
Frost Ming
1a0fea8b8e
fix: update README
Signed-off-by: Frost Ming <me@frostming.com>
2024-01-25 15:13:53 +08:00
Frost Ming
4882716d1c
feat: support python-version-file input
* feat: support python-version-file input

Signed-off-by: Frost Ming <me@frostming.com>

* fix: build esm

Signed-off-by: Frost Ming <me@frostming.com>

* fix: commonjs

Signed-off-by: Frost Ming <me@frostming.com>
2024-01-25 15:07:31 +08:00
Frost Ming
4b6ba52fde
chore: update project and lock files (#47) 2024-01-25 11:54:03 +08:00
Axel H
f94bfb2b4f
feat(node): update dependencies and build to target Node 20 (#46)
* build(node): update dependencies and build to target Node 20 and remove the build deprecation warning annotations

* ci: trigger build on pull requests
2024-01-25 11:16:20 +08:00
Frost Ming
0b61a6c732
doc: move the configuration to its own section
Signed-off-by: Frost Ming <me@frostming.com>
2023-09-06 11:07:29 +08:00
Frost Ming
ddc33ca746
fix: change url
Signed-off-by: Frost Ming <me@frostming.com>
2023-08-02 10:58:52 +08:00
David Montague
c287ac6f97
fix: Add pypy- prefix to version used for cache key when appropriate (#39)
Add `pypy-` prefix to version used for cache key when appropriate.

Signed-off-by: Frost Ming <me@frostming.com>
2023-07-25 17:59:25 +08:00
Frost Ming
c21af6fa77
doc: update README
Signed-off-by: Frost Ming <me@frostming.com>
2023-07-25 17:23:09 +08:00
Frost Ming
c21a0792fc
feat: add update-python input
Signed-off-by: Frost Ming <me@frostming.com>
2023-07-25 17:21:26 +08:00
Frost Ming
2d86acd19c
fix: Give allow-python-prereleases a default value
Fix #36

Signed-off-by: Frost Ming <me@frostming.com>
2023-06-24 17:43:12 +08:00
Timothée Mazzucotelli
6f13d8d292
feat: Fallback on prerelease like setup-python does (#35)
* feat: Fallback on prerelease like setup-python does

* fixup! feat: Fallback on prerelease like setup-python does

* fixup! feat: Fallback on prerelease like setup-python does

* fixup! feat: Fallback on prerelease like setup-python does

* fixup! feat: Fallback on prerelease like setup-python does

* fixup! feat: Fallback on prerelease like setup-python does
2023-06-21 17:08:31 +08:00
Frost Ming
f637ad9fac
fix: use new install script url
Signed-off-by: Frost Ming <me@frostming.com>
2023-06-19 18:24:28 +08:00
Thiago Lages de Alencar
a70a002bdd
Change to use virtualenv as default (#33)
PEP 582 has become an opt-in feature in PDM
2023-06-15 15:29:30 +08:00
Trim21
202fe0828e
set esbuild target to node16 (#30) 2023-05-03 08:00:42 +08:00
Frost Ming
5e2c2de7b2
chore: add lockfile
Signed-off-by: Frost Ming <me@frostming.com>
2023-04-28 14:38:35 +08:00
Thiago Lages de Alencar
70bb221e37
Remove install-output.json (#28) 2023-01-31 08:30:48 +08:00
Tyler Baur
97e52c626f
Remove extraneous ```yaml (#26)
Remove the extra ```yaml so it renders properly.
2023-01-31 08:30:10 +08:00
Frost Ming
a3345616b1
fix: try to use python3 if possible 2022-10-27 11:30:55 +08:00
Frost Ming
ed9b6c5626
fix: post action run even if cache is false (#24) 2022-10-21 22:17:30 +08:00
Frost Ming
5f2990033f
feat: built-in cache support (#22) 2022-10-21 12:06:56 +08:00
Frost Ming
1c39d42ed6
feat: Use the install script to install PDM in isolated environment (#21) 2022-10-21 10:19:30 +08:00
Frost Ming
21f59457b4
feat: Update action to deliminate the deprecation warnings (#20)
* feat: Update to deliminate deprecation warnings

* update dependencies

* change to the new API

* update env

* update dist js
2022-10-17 16:28:14 +08:00
18 changed files with 147546 additions and 7165 deletions

View File

@ -1,4 +1,7 @@
on: [push] on:
push:
branches: [main]
pull_request:
name: Test Action name: Test Action
@ -7,15 +10,25 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
python-version: [3.7, 3.8, 3.9, "3.10"] python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
os: ["windows-latest", "ubuntu-latest"] os: [windows-latest, ubuntu-latest, macos-latest]
name: Test the action name: Test the action
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup PDM - name: Setup PDM
uses: ./ uses: ./
id: setup-pdm
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
cache: true
allow-python-prereleases: true
- name: Check output
run: |
echo ${{ steps.setup-pdm.outputs.pdm-bin }}
echo ${{ steps.setup-pdm.outputs.pdm-version }}
echo ${{ steps.setup-pdm.outputs.python-path }}
echo ${{ steps.setup-pdm.outputs.python-version }}
- name: Install dependencies - name: Install dependencies
run: pdm install -v && pdm info run: pdm install -v && pdm info

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
node_modules/ node_modules/
yarn.lock yarn.lock
__pypackages__/ __pypackages__/
.pdm.toml .pdm-python

View File

@ -4,27 +4,86 @@ A GitHub Action that installs pdm properly for all Python versions
## Why do I need this action? ## Why do I need this action?
As you know, PDM requires Python 3.7 and higher to install the package, while till now(March 2021) Python 3.6 is still widely used by many libraries. The version requirement will prevent potential users from adopting PDM. However, it is a misunderstanding, PDM CAN run projects using Python 3.6 or even Python 2! Nowadays the main reason to use this action is that `actions/setup-python` [doesn't support](https://github.com/actions/setup-python/issues/587#issuecomment-1455797407) caching for PDM out of the box while `setup-pdm` does.
But it is still not obvious and it is a pain for developers to properly build their CI workflows. So I made `pdm-project/setup-pdm` to solve the problem. It is PDM-for-CI done right!
Historically, this action made it easier to use PDM in repos where the Python version in use was older than the Python version required by PDM. PDM requires >=3.8 but works for projects using older versions.
## Usage ## Usage
Include the action in your workflow yaml file with the following arguments: Include the action in your workflow yaml:
```yaml ```yaml
steps: steps:
... - uses: actions/checkout@v4
- uses: pdm-project/setup-pdm@main - name: Setup PDM
name: Setup PDM uses: pdm-project/setup-pdm@v4
with: # You are now able to use PDM in your workflow
python-version: 3.8 # Version range or exact version of a Python version to use, the same as actions/setup-python
architecture: x64 # The target architecture (x86, x64) of the Python interpreter. the same as actions/setup-python
version: 1.4.0 # The version of PDM to install. Leave it as empty to use the latest version from PyPI
prerelease: true # Allow prerelease versions to be installed
enable-pep582: true # Enable PEP 582 package loading globally
- name: Install dependencies - name: Install dependencies
run: pdm install # Then you can use pdm in the following steps. run: pdm install
...
``` ```
You don't need `actions/setup-python` actually. You don't need `actions/setup-python` actually.
## Action Inputs
This action supports the following inputs:
| Input | Default | Description |
| -------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `python-version` | Not specified | Version range or exact version of a Python version to use, using SemVer's version range syntax. |
| `python-version-file` | `pyproject.toml` | File containing the Python version to use. Example: .`python-version` |
| `architecture` | `x64` | The target architecture (x86, x64, arm64) of the Python interpreter. |
| `allow-python-prereleases` | `false` | Allow prerelease versions of Python to be installed. |
| `token` | `${{ github.token }}` | Used to pull python distributions from actions/python-versions. Since there's a default, this is typically not supplied by the user. |
| `version` | Not specified | The version of PDM to install, or 'head' to install from the main branch. |
| `prerelease` | `false` | Allow prerelease versions of PDM to be installed |
| `enable-pep582` | `false` | Enable PEP 582 package loading globally. |
| `cache` | `false` | Cache PDM installation. |
| `cache-dependency-path` | `pdm.lock` | The dependency file(s) to cache. |
| `update-python` | `true` | Whether to update the environment with the requested Python |
## Action Outputs
This action also exposes the following outputs:
| Output | Description |
| ---------------- | --------------------------------------------------------------------------------- |
| `python-version` | The installed Python or PyPy version. Useful when given a version range as input. |
| `python-path` | The absolute path to the Python or PyPy executable. |
| `pdm-version` | The installed PDM version. |
| `pdm-bin` | The absolute path to the PDM executable. |
## Caches
This action has a built-in cache support. You can use it like this:
```yaml
- uses: pdm-project/setup-pdm@v3
with:
python-version: 3.9
cache: true
```
The default path to calculate the cache key is `./pdm.lock`, you can change it by setting the `cache-dependency-path` input.
**Using a list of file paths to cache dependencies**
```yaml
- uses: pdm-project/setup-pdm@v3
with:
python-version: 3.9
cache: true
cache-dependency-path: |
./pdm.lock
./pdm.new.lock
```
**Using a glob pattern to cache dependencies**
```yaml
- uses: pdm-project/setup-pdm@v3
with:
python-version: 3.9
cache: true
cache-dependency-path: '**/pdm.lock'
```

View File

@ -1,36 +1,67 @@
--- ---
name: "Setup PDM" name: Setup PDM
description: "Set up a specific version of PDM and uses a given Python version to work on" description: Set up a specific version of PDM and uses a given Python version to work on
author: "Frost Ming" author: Frost Ming
inputs: inputs:
python-version: python-version:
description: "Version range or exact version of a Python version to use, using SemVer's version range syntax." description: 'Version range or exact version of a Python version to use, using SemVer''s version range syntax.'
default: "3.x" python-version-file:
required: true description: 'File containing the Python version to use. Example: .python-version'
architecture: architecture:
description: "The target architecture (x86, x64) of the Python interpreter." description: 'The target architecture (x86, x64, arm64) of the Python interpreter.'
required: false
allow-python-prereleases:
description: Allow prerelease versions of Python to be installed.
default: 'false'
required: false required: false
token: token:
description: Used to pull python distributions from actions/python-versions. Since there's a default, this is typically not supplied by the user. description: Used to pull python distributions from actions/python-versions. Since there's a default, this is typically not supplied by the user.
default: ${{ github.token }} default: ${{ github.token }}
required: false required: false
version: version:
description: The version of PDM to install. description: The version of PDM to install, or 'head' to install from the main branch.
required: false
ref:
description: The Ref of GitHub Repository
required: false required: false
prerelease: prerelease:
description: Allow prerelease versions to be installed description: Allow prerelease versions to be installed
default: "false" default: 'false'
required: false required: false
enable-pep582: enable-pep582:
description: "Enable PEP 582 package loading globally." description: Enable PEP 582 package loading globally.
default: "true" default: 'false'
required: false required: false
cache:
description: Cache PDM installation.
default: 'false'
required: false
cache-dependency-path:
description: The dependency file(s) to cache.
default: pdm.lock
required: false
cache-restore-exact-match:
description: >
Restore cache ONLY on exact match with the primary key.
Note: Post-installation cache will still be saved if cache is 'true'.
default: 'false'
required: false
update-python:
description: Whether to update the environment with the requested Python
default: 'true'
outputs:
python-version:
description: The installed Python or PyPy version. Useful when given a version range as input.
python-path:
description: The absolute path to the Python or PyPy executable.
pdm-version:
description: The installed PDM version.
pdm-bin:
description: The absolute path to the PDM executable.
cache-hit:
description: Whether or not there was a cache hit.
runs: runs:
using: "node12" using: node20
main: "dist/setup-pdm.js" main: dist/setup-pdm.js
post: dist/cache-save.js
post-if: success()
branding: branding:
icon: "code" icon: code
color: "green" color: green

9
build.ts Normal file
View File

@ -0,0 +1,9 @@
import esbuild from 'esbuild'
esbuild.build({
platform: 'node',
target: 'node20',
bundle: true,
entryPoints: ['src/setup-pdm.ts', 'src/cache-save.ts'],
outdir: 'dist',
})

63968
dist/cache-save.js vendored Normal file

File diff suppressed because one or more lines are too long

80636
dist/setup-pdm.js vendored

File diff suppressed because one or more lines are too long

4
eslint.config.js Normal file
View File

@ -0,0 +1,4 @@
// eslint.config.js
const antfu = require('@antfu/eslint-config').default
module.exports = antfu()

View File

@ -1,25 +1,34 @@
{ {
"name": "setup-pdm", "name": "setup-pdm",
"version": "2.0.0", "version": "4.0.0",
"packageManager": "pnpm@8.14.3",
"description": "The GitHub Action for using pdm as the package manager", "description": "The GitHub Action for using pdm as the package manager",
"main": "dist/setup-pdm.js",
"scripts": {
"build": "esbuild src/setup-pdm.ts --bundle --platform=node --outfile=dist/setup-pdm.js"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/pdm-project/setup-pdm.git" "url": "git+https://github.com/pdm-project/setup-pdm.git"
}, },
"main": "dist/setup-pdm.js",
"scripts": {
"build": "esno build.ts",
"lint": "eslint .",
"lint:fix": "eslint . --fix"
},
"dependencies": { "dependencies": {
"@actions/core": "^1.2.6", "@actions/cache": "^4.0.3",
"@actions/exec": "^1.0.4", "@actions/core": "^1.10.1",
"semver": "^7.3.7", "@actions/exec": "^1.1.1",
"@actions/glob": "^0.4.0",
"got": "^14.0.0",
"semver": "^7.5.4",
"setup-python": "actions/setup-python" "setup-python": "actions/setup-python"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^14.14.31", "@antfu/eslint-config": "^2.4.6",
"@types/semver": "^7.3.4", "@types/node": "^18.11.0",
"esbuild": "^0.9.0", "@types/semver": "^7.5.4",
"typescript": "^4.2.2" "esbuild": "^0.19.12",
"eslint": "^8.56.0",
"esno": "^4.0.0",
"typescript": "^4.8.4"
} }
} }

98
pdm.lock generated
View File

@ -1,54 +1,70 @@
# This file is @generated by PDM.
# It is not intended for manual editing.
[metadata]
groups = ["default", "dev"]
strategy = ["inherit_metadata"]
lock_version = "4.5.0"
content_hash = "sha256:c7bc8c77abe4c890545158d7bfdd811dce4a2658fa8ab856aa152f869973efab"
[[metadata.targets]]
requires_python = ">=3.9"
[[package]] [[package]]
name = "certifi" name = "certifi"
version = "2022.6.15" version = "2023.11.17"
requires_python = ">=3.6" requires_python = ">=3.6"
summary = "Python package for providing Mozilla's CA Bundle." summary = "Python package for providing Mozilla's CA Bundle."
groups = ["dev"]
[[package]] marker = "python_version == \"3.9\""
name = "chardet" files = [
version = "5.0.0" {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"},
requires_python = ">=3.6" {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"},
summary = "Universal encoding detector for Python 3" ]
[[package]]
name = "idna"
version = "3.3"
requires_python = ">=3.5"
summary = "Internationalized Domain Names in Applications (IDNA)"
[[package]] [[package]]
name = "pytz" name = "pytz"
version = "2022.1" version = "2023.3.post1"
summary = "World timezone definitions, modern and historical" summary = "World timezone definitions, modern and historical"
groups = ["dev"]
marker = "python_version == \"3.10\""
files = [
{file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"},
{file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"},
]
[[package]]
name = "setuptools"
version = "69.0.3"
requires_python = ">=3.8"
summary = "Easily download, build, install, upgrade, and uninstall Python packages"
groups = ["dev"]
marker = "python_version == \"3.11\""
files = [
{file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"},
{file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"},
]
[[package]]
name = "six"
version = "1.16.0"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
summary = "Python 2 and 3 compatibility utilities"
groups = ["dev"]
marker = "python_version == \"3.12\""
files = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]
[[package]] [[package]]
name = "urllib3" name = "urllib3"
version = "1.26.10" version = "2.1.0"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" requires_python = ">=3.8"
summary = "HTTP library with thread-safe connection pooling, file post, and more." summary = "HTTP library with thread-safe connection pooling, file post, and more."
groups = ["dev"]
[metadata] marker = "python_version == \"3.13\""
lock_version = "4.0" files = [
content_hash = "sha256:9386b3d6ac959508ef3cf75fdab7c82bd440c0a79841a0786d71c1e42a58b24d" {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"},
{file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"},
[metadata.files]
"certifi 2022.6.15" = [
{url = "https://files.pythonhosted.org/packages/e9/06/d3d367b7af6305b16f0d28ae2aaeb86154fa91f144f036c2d5002a5a202b/certifi-2022.6.15-py3-none-any.whl", hash = "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"},
{url = "https://files.pythonhosted.org/packages/cc/85/319a8a684e8ac6d87a1193090e06b6bbb302717496380e225ee10487c888/certifi-2022.6.15.tar.gz", hash = "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d"},
]
"chardet 5.0.0" = [
{url = "https://files.pythonhosted.org/packages/4c/d1/1b96dd69fa42f20b70701b5cd42a75dd5f0c7a24dc0abfef35cc146210dc/chardet-5.0.0-py3-none-any.whl", hash = "sha256:d3e64f022d254183001eccc5db4040520c0f23b1a3f33d6413e099eb7f126557"},
{url = "https://files.pythonhosted.org/packages/31/a2/12c090713b3d0e141f367236d3a8bdc3e5fca0d83ff3647af4892c16c205/chardet-5.0.0.tar.gz", hash = "sha256:0368df2bfd78b5fc20572bb4e9bb7fb53e2c094f60ae9993339e8671d0afb8aa"},
]
"idna 3.3" = [
{url = "https://files.pythonhosted.org/packages/04/a2/d918dcd22354d8958fe113e1a3630137e0fc8b44859ade3063982eacd2a4/idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
{url = "https://files.pythonhosted.org/packages/62/08/e3fc7c8161090f742f504f40b1bccbfc544d4a4e09eb774bf40aafce5436/idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
]
"pytz 2022.1" = [
{url = "https://files.pythonhosted.org/packages/60/2e/dec1cc18c51b8df33c7c4d0a321b084cf38e1733b98f9d15018880fb4970/pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"},
{url = "https://files.pythonhosted.org/packages/2f/5f/a0f653311adff905bbcaa6d3dfaf97edcf4d26138393c6ccd37a484851fb/pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7"},
]
"urllib3 1.26.10" = [
{url = "https://files.pythonhosted.org/packages/68/47/93d3d28e97c7577f563903907912f4b3804054e4877a5ba6651f7182c53b/urllib3-1.26.10-py2.py3-none-any.whl", hash = "sha256:8298d6d56d39be0e3bc13c1c97d133f9b45d797169a0e11cdd0e0489d786f7ec"},
{url = "https://files.pythonhosted.org/packages/25/36/f056e5f1389004cf886bb7a8514077f24224238a7534497c014a6b9ac770/urllib3-1.26.10.tar.gz", hash = "sha256:879ba4d1e89654d9769ce13121e0f94310ea32e8d2f8cf587b77c08bbcdb30d6"},
] ]

3767
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +1,18 @@
[project] [project]
authors = [ name = "setup-pdm"
{name = "Frost Ming", email = "mianghong@gmail.com"}, version = "0.0.0"
] authors = [ { name = "Frost Ming", email = "mianghong@gmail.com" }, ]
include = "test.py" requires-python = ">=3.9"
requires-python = ">=3.6" license = { text = "MIT" }
dynamic = ["classifiers"]
license = {text = "MIT"}
[project.urls]
homepage = ""
[tool]
[tool.pdm] [tool.pdm]
distribution = false
[tool.pdm.dev-dependencies] [tool.pdm.dev-dependencies]
dev = [ dev = [
"idna; python_version=='3.6'",
"chardet; python_version=='3.7'",
"urllib3; python_version=='3.8'",
"certifi; python_version=='3.9'", "certifi; python_version=='3.9'",
"pytz; python_version=='3.10'" "pytz; python_version=='3.10'",
"setuptools; python_version=='3.11'",
"six; python_version=='3.12'",
"urllib3; python_version=='3.13'",
] ]
[build-system]
requires = ["pdm-pep517"]
build-backend = "pdm.pep517.api"

48
src/cache-save.ts Normal file
View File

@ -0,0 +1,48 @@
import fs from 'node:fs'
import * as core from '@actions/core'
import * as cache from '@actions/cache'
async function run() {
try {
const cache = core.getBooleanInput('cache')
if (cache)
await saveCache()
}
catch (error) {
const err = error as Error
core.setFailed(err.message)
}
// Explicit process.exit() to not wait for hanging promises,
// see https://github.com/actions/setup-node/issues/878
process.exit()
}
async function saveCache() {
const cachePaths = JSON.parse(core.getState('cache-paths')) as string[]
core.debug(`paths for caching are ${cachePaths.join(', ')}`)
if (cachePaths.every(path => !fs.existsSync(path)))
throw new Error(`Cache folder path is retrieved for pdm but doesn't exist on disk: ${cachePaths.join(', ')}`)
const primaryKey = core.getState('cache-primary-key')
const matchedKey = core.getState('cache-matched-key')
if (!primaryKey) {
core.warning('Error retrieving key from state.')
return
}
else if (matchedKey === primaryKey) {
// no change in target directories
core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`)
return
}
const cacheId = await cache.saveCache(cachePaths, primaryKey)
if (cacheId === -1)
return
core.info(`Cache saved with the key: ${primaryKey}`)
}
run()

63
src/caches.ts Normal file
View File

@ -0,0 +1,63 @@
import path from 'node:path'
import process from 'node:process'
import * as core from '@actions/core'
import * as cache from '@actions/cache'
import { hashFiles } from '@actions/glob'
import { getOutput } from './utils'
async function calculateCacheKeys(pythonVersion: string, cacheDependencyPath: string): Promise<{ primaryKey: string, restoreKeys: string[] }> {
const hash = await hashFiles(cacheDependencyPath)
const primaryKey = `setup-pdm-${process.env.RUNNER_OS}-${process.env.RUNNER_ARCH}-python-${pythonVersion}-${hash}`
const restoreKey = `setup-pdm-${process.env.RUNNER_OS}-${process.env.RUNNER_ARCH}-python-${pythonVersion}-`
const restoreExactMatch = core.getBooleanInput('cache-restore-exact-match')
if (restoreExactMatch) {
return { primaryKey, restoreKeys: [] }
}
return { primaryKey, restoreKeys: [restoreKey] }
}
async function cacheDependencies(pdmBin: string, pythonVersion: string) {
const cacheDependencyPath = core.getInput('cache-dependency-path') || 'pdm.lock'
const { primaryKey, restoreKeys } = await calculateCacheKeys(pythonVersion, cacheDependencyPath)
if (primaryKey.endsWith('-')) {
throw new Error(
`No file in ${process.cwd()} matched to [${cacheDependencyPath
.split('\n')
.join(',')}], make sure you have checked out the target repository`,
)
}
const cachePath = await getCacheDirectories(pdmBin)
core.saveState('cache-paths', cachePath)
core.saveState('cache-primary-key', primaryKey)
const matchedKey = await cache.restoreCache(cachePath, primaryKey, restoreKeys)
handleMatchResult(matchedKey, primaryKey)
}
async function getCacheDirectories(pdmBin: string): Promise<string[]> {
const paths = [
path.join(process.cwd(), '.venv'),
path.join(process.cwd(), '__pypackages__'),
]
paths.push(await getOutput(pdmBin, ['config', 'cache_dir']))
paths.push(await getOutput(pdmBin, ['config', 'venv.location']))
return paths
}
function handleMatchResult(matchedKey: string | undefined, primaryKey: string) {
if (matchedKey) {
core.saveState('cache-matched-key', matchedKey)
core.info(`Cache restored from key: ${matchedKey}`)
}
else {
core.info(`pdm cache is not found`)
}
core.setOutput('cache-hit', matchedKey === primaryKey)
}
export { cacheDependencies }

View File

@ -1,58 +1,75 @@
import * as os from 'node:os'
import path from 'node:path'
import { promises as fs } from 'node:fs'
import process from 'node:process'
import * as core from '@actions/core' import * as core from '@actions/core'
import * as exec from '@actions/exec' import { exec } from '@actions/exec'
import * as setupPython from 'setup-python/src/find-python'
import { IS_WINDOWS } from 'setup-python/src/utils' import { IS_WINDOWS } from 'setup-python/src/utils'
import * as os from 'os'
import { promises as fs } from 'fs'
import path from 'path'
import semParse from 'semver/functions/parse' import semParse from 'semver/functions/parse'
import semIntersect from 'semver/ranges/intersects' import * as utils from './utils'
import { cacheDependencies } from './caches'
const PDM_PYTHON_REQUIRES = '>=3.7' const INSTALL_SCRIPT_URL = 'https://pdm.fming.dev/install-pdm.py'
const FALLBACK_INSTALL_VERSION = '3.10' interface InstallOutput {
const GITHUB_REPO = 'https://github.com/pdm-project/pdm.git' pdm_version: string
pdm_bin: string
install_python_version: string
install_location: string
}
function getPep582Path(version: string): string { function getPep582Path(installDir: string, pythonVersion: string): string {
const installDir = process.env.pythonLocation || '' const parsedVersion = semParse(pythonVersion)!
const parsedVersion = semParse(version)! if (IS_WINDOWS)
if (IS_WINDOWS) {
return path.resolve(installDir, 'Lib/site-packages/pdm/pep582') return path.resolve(installDir, 'Lib/site-packages/pdm/pep582')
} else { else
return path.resolve(installDir, 'lib', `python${parsedVersion.major}.${parsedVersion.minor}`, 'site-packages/pdm/pep582') return path.resolve(installDir, 'lib', `python${parsedVersion.major}.${parsedVersion.minor}`, 'site-packages/pdm/pep582')
}
} }
async function run(): Promise<void> { async function run(): Promise<void> {
const arch = core.getInput('architecture') || os.arch() const arch = core.getInput('architecture') || os.arch()
const pdmVersion = core.getInput('version') const pdmVersion = core.getInput('version')
const pythonVersion = core.getInput('python-version') const pythonVersion = utils.resolveVersionInput()[0] || '3.x'
const versionCompatible = semIntersect(PDM_PYTHON_REQUIRES, pythonVersion) const updateEnvironment = core.getBooleanInput('update-python')
const ref = core.getInput('ref') const allowPythonPreReleases = core.getBooleanInput('allow-python-prereleases')
const pdmPackage = pdmVersion ? `pdm==${pdmVersion}` : ref ? `pdm @ git+${GITHUB_REPO}@${ref}` : 'pdm' const cmdArgs = ['-']
const cmdArgs = ['-m', 'pip', 'install', '-U', pdmPackage] if (core.getBooleanInput('prerelease'))
if (core.getInput('prerelease') === 'true') { cmdArgs.push('--prerelease')
cmdArgs.push('--pre')
} if (pdmVersion)
cmdArgs.push('--version', pdmVersion)
cmdArgs.push('-o', 'install-output.json')
// Use the default python version installed with the runner
try { try {
let installedPython = await setupPython.findPythonVersion(versionCompatible ? pythonVersion : FALLBACK_INSTALL_VERSION, arch) const installedPython = await utils.findPythonVersion(pythonVersion, arch, allowPythonPreReleases, updateEnvironment)
await exec.exec('python', cmdArgs)
if (core.getInput('enable-pep582') === 'true') {
core.exportVariable('PYTHONPATH', getPep582Path(installedPython.version))
}
if (!versionCompatible) {
installedPython = await setupPython.findPythonVersion(pythonVersion, arch)
}
const pythonBin = path.join(process.env.pythonLocation as string, IS_WINDOWS ? 'python.exe' : 'bin/python').replace(/\\/g, '/')
await fs.writeFile('.pdm.toml', `[python]\npath="${pythonBin}"\n`)
const { stdout: pdmVersionOutput } = await exec.getExecOutput('pdm --version')
if (process.platform === 'linux') { if (process.platform === 'linux') {
// See https://github.com/actions/virtual-environments/issues/2803 // See https://github.com/actions/virtual-environments/issues/2803
if (process.arch === 'x64') {
core.exportVariable('LD_PRELOAD', '/lib/x86_64-linux-gnu/libgcc_s.so.1') core.exportVariable('LD_PRELOAD', '/lib/x86_64-linux-gnu/libgcc_s.so.1')
} }
core.info(`Successfully setup ${pdmVersionOutput} with Python ${installedPython.version}`) else if (process.arch === 'arm64') {
core.exportVariable('LD_PRELOAD', '/lib/aarch64-linux-gnu/libgcc_s.so.1')
}
}
await exec(IS_WINDOWS ? 'python' : 'python3', cmdArgs, { input: await utils.fetchUrlAsBuffer(INSTALL_SCRIPT_URL) })
const installOutput: InstallOutput = JSON.parse(await utils.readFile('install-output.json'))
core.debug(`Install output: ${installOutput}`)
core.info(`Successfully setup ${installOutput.pdm_version} with Python ${installedPython}`)
core.setOutput('pdm-version', installOutput.pdm_version)
core.setOutput('pdm-bin', path.join(installOutput.install_location, installOutput.pdm_bin))
core.addPath(path.dirname(installOutput.pdm_bin))
if (core.getBooleanInput('enable-pep582'))
core.exportVariable('PYTHONPATH', getPep582Path(installOutput.install_location, installOutput.install_python_version))
const matchersPath = path.join(__dirname, '..', '.github') const matchersPath = path.join(__dirname, '..', '.github')
core.info(`##[add-matcher]${path.join(matchersPath, 'python.json')}`) core.info(`##[add-matcher]${path.join(matchersPath, 'python.json')}`)
} catch (error: any) { if (utils.isCacheAvailable())
await cacheDependencies(installOutput.pdm_bin, installedPython)
await fs.rm('install-output.json')
}
catch (error: any) {
core.setFailed(error.message) core.setFailed(error.message)
} }
} }

123
src/utils.ts Normal file
View File

@ -0,0 +1,123 @@
import fs from 'node:fs'
import { Buffer } from 'node:buffer'
import * as core from '@actions/core'
import * as cache from '@actions/cache'
import got from 'got'
import { useCpythonVersion } from 'setup-python/src/find-python'
import { findPyPyVersion } from 'setup-python/src/find-pypy'
import {
getVersionInputFromFile,
getVersionInputFromTomlFile,
logWarning,
} from 'setup-python/src/utils'
import { getExecOutput } from '@actions/exec'
function isPyPyVersion(versionSpec: string): boolean {
return versionSpec.startsWith('pypy')
}
export async function fetchUrlAsBuffer(url: string): Promise<Buffer> {
const response = await got(url)
if (!response.ok)
throw new Error(`Failed to fetch ${url}`)
return Buffer.from(response.body)
}
export async function findPythonVersion(version: string, architecture: string, allowPreReleases: boolean, updateEnvironment: boolean = true): Promise<string> {
let pythonVersion = ''
if (isPyPyVersion(version)) {
const installed = await findPyPyVersion(
version,
architecture,
updateEnvironment,
false,
allowPreReleases,
)
pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`
core.info(
`Successfully set up PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})`,
)
return `pypy-${installed.resolvedPythonVersion}`
}
else {
const installed = await useCpythonVersion(
version,
architecture,
updateEnvironment,
false,
allowPreReleases,
)
pythonVersion = installed.version
core.info(`Successfully set up ${installed.impl} (${pythonVersion})`)
return installed.version
}
}
export async function readFile(filePath: string): Promise<string> {
return await fs.promises.readFile(filePath, 'utf8')
}
export async function getOutput(command: string, args: string[]): Promise<string> {
const { stdout, exitCode, stderr } = await getExecOutput(command, args)
if (exitCode && stderr)
throw new Error(`Could not run ${command} ${args.join(' ')}: ${stderr}`)
return stdout.trim()
}
export function isCacheAvailable(): boolean {
if (!core.getBooleanInput('cache'))
return false
if (!cache.isFeatureAvailable()) {
core.warning('Caching is not supported on this platform.')
return false
}
return true
}
function resolveVersionInputFromDefaultFile(): string[] {
const couples: [string, (versionFile: string) => string[]][] = [
['pyproject.toml', getVersionInputFromTomlFile],
]
for (const [versionFile, _fn] of couples) {
logWarning(
`Neither 'python-version' nor 'python-version-file' inputs were supplied. Attempting to find '${versionFile}' file.`,
)
if (fs.existsSync(versionFile))
return _fn(versionFile)
else
logWarning(`${versionFile} doesn't exist.`)
}
return []
}
export function resolveVersionInput() {
let versions = core.getMultilineInput('python-version')
const versionFile = core.getInput('python-version-file')
if (versions.length) {
if (versionFile) {
core.warning(
'Both python-version and python-version-file inputs are specified, only python-version will be used.',
)
}
}
else {
if (versionFile) {
if (!fs.existsSync(versionFile)) {
throw new Error(
`The specified python version file at: ${versionFile} doesn't exist.`,
)
}
versions = getVersionInputFromFile(versionFile)
}
else {
versions = resolveVersionInputFromDefaultFile()
}
}
return versions
}

View File

@ -1,15 +1,14 @@
import importlib
import os import os
import sys import sys
import unittest import unittest
import importlib
PACKAGE_MAP = { PACKAGE_MAP = {
"3.6": "idna",
"3.7": "chardet",
"3.8": "urllib3",
"3.9": "certifi", "3.9": "certifi",
"3.10": "pytz", "3.10": "pytz",
"3.11": "setuptools",
"3.12": "six",
"3.13": "urllib3",
} }

View File

@ -2,17 +2,9 @@
"compilerOptions": { "compilerOptions": {
/* Basic Options */ /* Basic Options */
// "incremental": true, /* Enable incremental compilation */ // "incremental": true, /* Enable incremental compilation */
"target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */, "target": "ESNext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
"allowJs": true /* Allow javascript files to be compiled. */,
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./dist" /* Redirect output structure to the directory. */,
"rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, "rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
"module": "CommonJS" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
// "composite": true, /* Enable project compilation */ // "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */ // "removeComments": true, /* Do not emit comments to output. */
@ -23,6 +15,14 @@
/* Strict Type-Checking Options */ /* Strict Type-Checking Options */
"strict": true /* Enable all strict type-checking options. */, "strict": true /* Enable all strict type-checking options. */,
// "allowJs": true /* Allow javascript files to be compiled. */,
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./lib" /* Redirect output structure to the directory. */,
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */ // "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */