Compare commits

...

15 Commits
v3 ... 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
17 changed files with 92195 additions and 87930 deletions

View File

@ -1,4 +1,7 @@
on: [push]
on:
push:
branches: [main]
pull_request:
name: Test Action
@ -7,8 +10,8 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
os: ["windows-latest", "ubuntu-latest", "macos-latest"]
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
os: [windows-latest, ubuntu-latest, macos-latest]
name: Test the action
steps:
- uses: actions/checkout@v3

View File

@ -4,48 +4,54 @@ A GitHub Action that installs pdm properly for all Python versions
## 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!
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!
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.
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
Include the action in your workflow yaml file with the following arguments:
Include the action in your workflow yaml:
```yaml
steps:
...
- uses: pdm-project/setup-pdm@v3
name: Setup PDM
with:
python-version: 3.9 # 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: 2.7.4 # The version of PDM to install. Leave it as empty to use the latest version from PyPI, or 'head' to use the latest version from GitHub
prerelease: false # Allow prerelease versions of PDM to be installed
enable-pep582: false # Enable PEP 582 package loading globally
allow-python-prereleases: false # Allow prerelease versions of Python to be installed. For example if only 3.12-dev is available, 3.12 will fallback to 3.12-dev
update-python: true # Update the environment with the requested python version
- uses: actions/checkout@v4
- name: Setup PDM
uses: pdm-project/setup-pdm@v4
# You are now able to use PDM in your workflow
- 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.
## 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:
```yaml
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."
```
| 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

View File

@ -1,18 +1,18 @@
---
name: "Setup PDM"
description: "Set up a specific version of PDM and uses a given Python version to work on"
author: "Frost Ming"
name: Setup PDM
description: Set up a specific version of PDM and uses a given Python version to work on
author: Frost Ming
inputs:
python-version:
description: "Version range or exact version of a Python version to use, using SemVer's version range syntax."
default: "3.x"
required: false
description: 'Version range or exact version of a Python version to use, using SemVer''s version range syntax.'
python-version-file:
description: 'File containing the Python version to use. Example: .python-version'
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"
description: Allow prerelease versions of Python to be installed.
default: 'false'
required: false
token:
description: Used to pull python distributions from actions/python-versions. Since there's a default, this is typically not supplied by the user.
@ -23,39 +23,45 @@ inputs:
required: false
prerelease:
description: Allow prerelease versions to be installed
default: "false"
default: 'false'
required: false
enable-pep582:
description: "Enable PEP 582 package loading globally."
default: "false"
description: Enable PEP 582 package loading globally.
default: 'false'
required: false
cache:
description: "Cache PDM installation."
default: "false"
description: Cache PDM installation.
default: 'false'
required: false
cache-dependency-path:
description: "The dependency file(s) to cache."
default: "pdm.lock"
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"
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."
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."
description: The absolute path to the Python or PyPy executable.
pdm-version:
description: "The installed PDM version."
description: The installed PDM version.
pdm-bin:
description: "The absolute path to the PDM executable."
description: The absolute path to the PDM executable.
cache-hit:
description: "Whether or not there was a cache hit."
description: Whether or not there was a cache hit.
runs:
using: "node16"
main: "dist/setup-pdm.js"
post: "dist/cache-save.js"
using: node20
main: dist/setup-pdm.js
post: dist/cache-save.js
post-if: success()
branding:
icon: "code"
color: "green"
icon: code
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',
})

81242
dist/cache-save.js vendored

File diff suppressed because one or more lines are too long

91987
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,29 +1,34 @@
{
"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",
"main": "dist/setup-pdm.js",
"scripts": {
"build": "esbuild src/setup-pdm.ts --bundle --platform=node --target=node16 --outfile=dist/setup-pdm.js && esbuild src/cache-save.ts --bundle --platform=node --target=node16 --outfile=dist/cache-save.js"
},
"packageManager": "pnpm@7.32.2",
"repository": {
"type": "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": {
"@actions/cache": "^3.0.6",
"@actions/core": "^1.10.0",
"@actions/cache": "^4.0.3",
"@actions/core": "^1.10.1",
"@actions/exec": "^1.1.1",
"@actions/glob": "^0.3.0",
"got": "^12.5.2",
"semver": "^7.3.8",
"@actions/glob": "^0.4.0",
"got": "^14.0.0",
"semver": "^7.5.4",
"setup-python": "actions/setup-python"
},
"devDependencies": {
"@antfu/eslint-config": "^2.4.6",
"@types/node": "^18.11.0",
"@types/semver": "^7.3.12",
"esbuild": "^0.15.11",
"@types/semver": "^7.5.4",
"esbuild": "^0.19.12",
"eslint": "^8.56.0",
"esno": "^4.0.0",
"typescript": "^4.8.4"
}
}

97
pdm.lock generated
View File

@ -1,79 +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]]
name = "certifi"
version = "2022.6.15"
version = "2023.11.17"
requires_python = ">=3.6"
summary = "Python package for providing Mozilla's CA Bundle."
[[package]]
name = "chardet"
version = "5.0.0"
requires_python = ">=3.6"
summary = "Universal encoding detector for Python 3"
[[package]]
name = "idna"
version = "3.3"
requires_python = ">=3.5"
summary = "Internationalized Domain Names in Applications (IDNA)"
groups = ["dev"]
marker = "python_version == \"3.9\""
files = [
{file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"},
{file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"},
]
[[package]]
name = "pytz"
version = "2022.1"
version = "2023.3.post1"
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 = "68.0.0"
requires_python = ">=3.7"
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]]
name = "urllib3"
version = "1.26.10"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4"
version = "2.1.0"
requires_python = ">=3.8"
summary = "HTTP library with thread-safe connection pooling, file post, and more."
[metadata]
lock_version = "4.2"
cross_platform = true
groups = ["default", "dev"]
content_hash = "sha256:1c3bf31e6d80f6c468b7d8948c19a5eda9014342869911f0895691955e061357"
[metadata.files]
"certifi 2022.6.15" = [
{url = "https://files.pythonhosted.org/packages/cc/85/319a8a684e8ac6d87a1193090e06b6bbb302717496380e225ee10487c888/certifi-2022.6.15.tar.gz", hash = "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d"},
{url = "https://files.pythonhosted.org/packages/e9/06/d3d367b7af6305b16f0d28ae2aaeb86154fa91f144f036c2d5002a5a202b/certifi-2022.6.15-py3-none-any.whl", hash = "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"},
]
"chardet 5.0.0" = [
{url = "https://files.pythonhosted.org/packages/31/a2/12c090713b3d0e141f367236d3a8bdc3e5fca0d83ff3647af4892c16c205/chardet-5.0.0.tar.gz", hash = "sha256:0368df2bfd78b5fc20572bb4e9bb7fb53e2c094f60ae9993339e8671d0afb8aa"},
{url = "https://files.pythonhosted.org/packages/4c/d1/1b96dd69fa42f20b70701b5cd42a75dd5f0c7a24dc0abfef35cc146210dc/chardet-5.0.0-py3-none-any.whl", hash = "sha256:d3e64f022d254183001eccc5db4040520c0f23b1a3f33d6413e099eb7f126557"},
]
"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/2f/5f/a0f653311adff905bbcaa6d3dfaf97edcf4d26138393c6ccd37a484851fb/pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7"},
{url = "https://files.pythonhosted.org/packages/60/2e/dec1cc18c51b8df33c7c4d0a321b084cf38e1733b98f9d15018880fb4970/pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"},
]
"setuptools 68.0.0" = [
{url = "https://files.pythonhosted.org/packages/c7/42/be1c7bbdd83e1bfb160c94b9cafd8e25efc7400346cf7ccdbdb452c467fa/setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"},
{url = "https://files.pythonhosted.org/packages/dc/98/5f896af066c128669229ff1aa81553ac14cfb3e5e74b6b44594132b8540e/setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"},
]
"six 1.16.0" = [
{url = "https://files.pythonhosted.org/packages/71/39/171f1c67cd00715f190ba0b100d606d440a28c93c7714febeca8b79af85e/six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
{url = "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
]
"urllib3 1.26.10" = [
{url = "https://files.pythonhosted.org/packages/25/36/f056e5f1389004cf886bb7a8514077f24224238a7534497c014a6b9ac770/urllib3-1.26.10.tar.gz", hash = "sha256:879ba4d1e89654d9769ce13121e0f94310ea32e8d2f8cf587b77c08bbcdb30d6"},
{url = "https://files.pythonhosted.org/packages/68/47/93d3d28e97c7577f563903907912f4b3804054e4877a5ba6651f7182c53b/urllib3-1.26.10-py2.py3-none-any.whl", hash = "sha256:8298d6d56d39be0e3bc13c1c97d133f9b45d797169a0e11cdd0e0489d786f7ec"},
groups = ["dev"]
marker = "python_version == \"3.13\""
files = [
{file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"},
{file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"},
]

3841
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +1,18 @@
[project]
authors = [
{name = "Frost Ming", email = "mianghong@gmail.com"},
]
include = "test.py"
requires-python = ">=3.6"
dynamic = ["classifiers"]
license = {text = "MIT"}
name = "setup-pdm"
version = "0.0.0"
authors = [ { name = "Frost Ming", email = "mianghong@gmail.com" }, ]
requires-python = ">=3.9"
license = { text = "MIT" }
[project.urls]
homepage = ""
[tool]
[tool.pdm]
distribution = false
[tool.pdm.dev-dependencies]
dev = [
"idna; python_version=='3.6'",
"chardet; python_version=='3.7'",
"urllib3; python_version=='3.8'",
"certifi; python_version=='3.9'",
"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"

View File

@ -1,45 +1,48 @@
import * as core from '@actions/core';
import * as cache from '@actions/cache';
import fs from 'fs';
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();
const cache = core.getBooleanInput('cache')
if (cache)
await saveCache()
}
} catch (error) {
const err = error as Error;
core.setFailed(err.message);
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[];
const cachePaths = JSON.parse(core.getState('cache-paths')) as string[]
core.debug(`paths for caching are ${cachePaths.join(', ')}`);
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(', ')}`);
}
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');
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) {
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;
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}`);
const cacheId = await cache.saveCache(cachePaths, primaryKey)
if (cacheId === -1)
return
core.info(`Cache saved with the key: ${primaryKey}`)
}
run();
run()

View File

@ -1,58 +1,63 @@
import path from 'path';
import * as core from '@actions/core';
import * as cache from '@actions/cache';
import { getOutput } from './utils';
import { hashFiles } from '@actions/glob';
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']}-python-${pythonVersion}-${hash}`;
const restoreKey = `setup-pdm-${process.env['RUNNER_OS']}-python-${pythonVersion}-`;
return { primaryKey, restoreKeys: [restoreKey] };
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);
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`
);
.join(',')}], make sure you have checked out the target repository`,
)
}
const cachePath = await getCacheDirectories(pdmBin);
const cachePath = await getCacheDirectories(pdmBin)
core.saveState('cache-paths', cachePath);
core.saveState('cache-primary-key', primaryKey);
core.saveState('cache-paths', cachePath)
core.saveState('cache-primary-key', primaryKey)
const matchedKey = await cache.restoreCache(cachePath, primaryKey, restoreKeys);
const matchedKey = await cache.restoreCache(cachePath, primaryKey, restoreKeys)
handleMatchResult(matchedKey, primaryKey);
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;
]
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.saveState('cache-matched-key', matchedKey)
core.info(`Cache restored from key: ${matchedKey}`)
}
core.setOutput('cache-hit', matchedKey === primaryKey);
else {
core.info(`pdm cache is not found`)
}
core.setOutput('cache-hit', matchedKey === primaryKey)
}
export { cacheDependencies };
export { cacheDependencies }

View File

@ -1,72 +1,77 @@
import * as os from 'os';
import path from 'path';
import * as core from '@actions/core';
import { exec } from '@actions/exec';
import { promises as fs } from 'fs';
import { IS_WINDOWS } from 'setup-python/src/utils';
import semParse from 'semver/functions/parse';
import * as utils from './utils';
import { cacheDependencies } from './caches';
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 { exec } from '@actions/exec'
import { IS_WINDOWS } from 'setup-python/src/utils'
import semParse from 'semver/functions/parse'
import * as utils from './utils'
import { cacheDependencies } from './caches'
const INSTALL_SCRIPT_URL = 'https://pdm.fming.dev/install-pdm.py';
const INSTALL_SCRIPT_URL = 'https://pdm.fming.dev/install-pdm.py'
interface InstallOutput {
pdm_version: string;
pdm_bin: string;
install_python_version: string;
install_location: string;
pdm_version: string
pdm_bin: string
install_python_version: string
install_location: string
}
function getPep582Path(installDir: string, pythonVersion: string): string {
const parsedVersion = semParse(pythonVersion)!;
if (IS_WINDOWS) {
return path.resolve(installDir, 'Lib/site-packages/pdm/pep582');
} else {
return path.resolve(installDir, 'lib', `python${parsedVersion.major}.${parsedVersion.minor}`, 'site-packages/pdm/pep582');
}
const parsedVersion = semParse(pythonVersion)!
if (IS_WINDOWS)
return path.resolve(installDir, 'Lib/site-packages/pdm/pep582')
else
return path.resolve(installDir, 'lib', `python${parsedVersion.major}.${parsedVersion.minor}`, 'site-packages/pdm/pep582')
}
async function run(): Promise<void> {
const arch = core.getInput('architecture') || os.arch();
const pdmVersion = core.getInput('version');
const pythonVersion = core.getInput('python-version');
const updateEnvironment = core.getBooleanInput('update-python');
const allowPythonPreReleases = core.getBooleanInput('allow-python-prereleases');
const cmdArgs = ['-'];
if (core.getBooleanInput('prerelease')) {
cmdArgs.push('--prerelease');
}
if (pdmVersion) {
cmdArgs.push('--version', pdmVersion);
}
cmdArgs.push('-o', 'install-output.json');
const arch = core.getInput('architecture') || os.arch()
const pdmVersion = core.getInput('version')
const pythonVersion = utils.resolveVersionInput()[0] || '3.x'
const updateEnvironment = core.getBooleanInput('update-python')
const allowPythonPreReleases = core.getBooleanInput('allow-python-prereleases')
const cmdArgs = ['-']
if (core.getBooleanInput('prerelease'))
cmdArgs.push('--prerelease')
if (pdmVersion)
cmdArgs.push('--version', pdmVersion)
cmdArgs.push('-o', 'install-output.json')
// Use the default python version installed with the runner
try {
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.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 installedPython = await utils.findPythonVersion(pythonVersion, arch, allowPythonPreReleases, updateEnvironment);
const installedPython = await utils.findPythonVersion(pythonVersion, arch, allowPythonPreReleases, updateEnvironment)
if (process.platform === 'linux') {
// See https://github.com/actions/virtual-environments/issues/2803
core.exportVariable('LD_PRELOAD', '/lib/x86_64-linux-gnu/libgcc_s.so.1');
if (process.arch === 'x64') {
core.exportVariable('LD_PRELOAD', '/lib/x86_64-linux-gnu/libgcc_s.so.1')
}
core.info(`Successfully setup ${installOutput.pdm_version} with Python ${installedPython}`);
const matchersPath = path.join(__dirname, '..', '.github');
core.info(`##[add-matcher]${path.join(matchersPath, 'python.json')}`);
if (utils.isCacheAvailable()) {
await cacheDependencies(installOutput.pdm_bin, installedPython);
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')
core.info(`##[add-matcher]${path.join(matchersPath, 'python.json')}`)
if (utils.isCacheAvailable())
await cacheDependencies(installOutput.pdm_bin, installedPython)
await fs.rm('install-output.json')
} catch (error: any) {
core.setFailed(error.message);
}
catch (error: any) {
core.setFailed(error.message)
}
}
run();
run()

View File

@ -1,75 +1,123 @@
import * as core from '@actions/core';
import * as cache from '@actions/cache';
import got from 'got';
import { promises as fs } from 'fs';
import { useCpythonVersion } from 'setup-python/src/find-python';
import { findPyPyVersion } from 'setup-python/src/find-pypy';
import { getExecOutput } from '@actions/exec';
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');
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);
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 = '';
let pythonVersion = ''
if (isPyPyVersion(version)) {
const installed = await findPyPyVersion(
version,
architecture,
updateEnvironment,
false,
allowPreReleases
);
pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`;
allowPreReleases,
)
pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`
core.info(
`Successfully set up PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})`
);
return `pypy-${installed.resolvedPythonVersion}`;
} else {
`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;
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.readFile(filePath, 'utf8');
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();
}
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 (!core.getBooleanInput('cache'))
return false
if (!cache.isFeatureAvailable()) {
core.warning('Caching is not supported on this platform.');
return false;
core.warning('Caching is not supported on this platform.')
return false
}
return true;
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,17 +1,14 @@
import importlib
import os
import sys
import unittest
import importlib
PACKAGE_MAP = {
"3.6": "idna",
"3.7": "chardet",
"3.8": "urllib3",
"3.9": "certifi",
"3.10": "pytz",
"3.11": "setuptools",
"3.12": "six",
"3.13": "urllib3",
}

View File

@ -2,17 +2,9 @@
"compilerOptions": {
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es6" /* 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": "./lib" /* Redirect output structure to the directory. */,
"target": "ESNext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
"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 */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
@ -23,6 +15,14 @@
/* 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. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */