mirror of
				https://kkgithub.com/actions/setup-python.git
				synced 2025-11-04 12:44:05 +08:00 
			
		
		
		
	Add check-latest functionality (#406)
This commit is contained in:
		
							
								
								
									
										33
									
								
								.github/workflows/test-pypy.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								.github/workflows/test-pypy.yml
									
									
									
									
										vendored
									
									
								
							@ -91,3 +91,36 @@ jobs:
 | 
			
		||||
 | 
			
		||||
      - name: Run simple code
 | 
			
		||||
        run: ${{ steps.setup-python.outputs.python-path }} -c 'import math; print(math.factorial(5))'
 | 
			
		||||
 | 
			
		||||
  check-latest:
 | 
			
		||||
    runs-on: ${{ matrix.os }}
 | 
			
		||||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      matrix:
 | 
			
		||||
        os: [ubuntu-latest, windows-latest, macos-latest]
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/checkout@v3
 | 
			
		||||
      - name: Setup PyPy and check latest
 | 
			
		||||
        uses: ./
 | 
			
		||||
        with:
 | 
			
		||||
          python-version: 'pypy-3.7-v7.3.x'
 | 
			
		||||
          check-latest: true
 | 
			
		||||
      - name: PyPy and Python version
 | 
			
		||||
        run: python --version
 | 
			
		||||
 | 
			
		||||
      - name: Run simple code
 | 
			
		||||
        run: python -c 'import math; print(math.factorial(5))'
 | 
			
		||||
 | 
			
		||||
      - name: Assert PyPy is running
 | 
			
		||||
        run: |
 | 
			
		||||
          import platform
 | 
			
		||||
          assert platform.python_implementation().lower() == "pypy"
 | 
			
		||||
        shell: python
 | 
			
		||||
 | 
			
		||||
      - name: Assert expected binaries (or symlinks) are present
 | 
			
		||||
        run: |
 | 
			
		||||
          EXECUTABLE="pypy-3.7-v7.3.x"
 | 
			
		||||
          EXECUTABLE=${EXECUTABLE/-/}  # remove the first '-' in "pypy-X.Y" -> "pypyX.Y" to match executable name
 | 
			
		||||
          EXECUTABLE=${EXECUTABLE%%-*}  # remove any -* suffixe
 | 
			
		||||
          ${EXECUTABLE} --version
 | 
			
		||||
        shell: bash
 | 
			
		||||
							
								
								
									
										24
									
								
								.github/workflows/test-python.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								.github/workflows/test-python.yml
									
									
									
									
										vendored
									
									
								
							@ -172,3 +172,27 @@ jobs:
 | 
			
		||||
 | 
			
		||||
    - name: Run simple code
 | 
			
		||||
      run: ${{ steps.setup-python.outputs.python-path }} -c 'import math; print(math.factorial(5))'
 | 
			
		||||
 | 
			
		||||
  check-latest:
 | 
			
		||||
    runs-on: ${{ matrix.os }}
 | 
			
		||||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      matrix:
 | 
			
		||||
        os: [ubuntu-latest, windows-latest, macos-latest]
 | 
			
		||||
        python-version: ["3.8", "3.9", "3.10"]
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/checkout@v3
 | 
			
		||||
      - name: Setup Python and check latest
 | 
			
		||||
        uses: ./
 | 
			
		||||
        with:
 | 
			
		||||
          python-version: ${{ matrix.python-version }}
 | 
			
		||||
          check-latest: true
 | 
			
		||||
      - name: Validate version
 | 
			
		||||
        run: |
 | 
			
		||||
          $pythonVersion = (python --version)
 | 
			
		||||
          if ("$pythonVersion" -NotMatch "${{ matrix.python }}"){
 | 
			
		||||
            Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python }}"
 | 
			
		||||
            exit 1
 | 
			
		||||
          }
 | 
			
		||||
          $pythonVersion
 | 
			
		||||
        shell: pwsh
 | 
			
		||||
							
								
								
									
										32
									
								
								.licenses/npm/@actions/http-client.dep.yml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										32
									
								
								.licenses/npm/@actions/http-client.dep.yml
									
									
									
										generated
									
									
									
								
							@ -1,32 +0,0 @@
 | 
			
		||||
---
 | 
			
		||||
name: "@actions/http-client"
 | 
			
		||||
version: 1.0.11
 | 
			
		||||
type: npm
 | 
			
		||||
summary: Actions Http Client
 | 
			
		||||
homepage: https://github.com/actions/http-client#readme
 | 
			
		||||
license: mit
 | 
			
		||||
licenses:
 | 
			
		||||
- sources: LICENSE
 | 
			
		||||
  text: |
 | 
			
		||||
    Actions Http Client for Node.js
 | 
			
		||||
 | 
			
		||||
    Copyright (c) GitHub, Inc.
 | 
			
		||||
 | 
			
		||||
    All rights reserved.
 | 
			
		||||
 | 
			
		||||
    MIT License
 | 
			
		||||
 | 
			
		||||
    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 | 
			
		||||
    associated documentation files (the "Software"), to deal in the Software without restriction,
 | 
			
		||||
    including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | 
			
		||||
    and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
 | 
			
		||||
    subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
    THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 | 
			
		||||
    LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
 | 
			
		||||
    NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 | 
			
		||||
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 | 
			
		||||
    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		||||
notices: []
 | 
			
		||||
							
								
								
									
										18
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								README.md
									
									
									
									
									
								
							@ -259,6 +259,24 @@ pypy3.7-nightly or pypy-3.7-nightly # Python 3.7 and nightly PyPy
 | 
			
		||||
 | 
			
		||||
Note: `pypy2` and `pypy3` have been removed in v3. Use the format above instead.
 | 
			
		||||
 | 
			
		||||
# Check latest version
 | 
			
		||||
 | 
			
		||||
The `check-latest` flag defaults to `false`. Use the default or set `check-latest` to `false` if you prefer stability and if you want to ensure a specific `Python/PyPy` version is always used.
 | 
			
		||||
 | 
			
		||||
If `check-latest` is set to `true`, the action first checks if the cached version is the latest one. If the locally cached version is not the most up-to-date, a `Python/PyPy` version will then be downloaded. Set `check-latest` to `true` if you want the most up-to-date `Python/PyPy` version to always be used.
 | 
			
		||||
 | 
			
		||||
> Setting `check-latest` to `true` has performance implications as downloading `Python/PyPy` versions is slower than using cached versions.
 | 
			
		||||
 | 
			
		||||
```yaml
 | 
			
		||||
steps:
 | 
			
		||||
  - uses: actions/checkout@v3
 | 
			
		||||
  - uses: actions/setup-python@v3
 | 
			
		||||
    with:
 | 
			
		||||
      python-version: '3.7'
 | 
			
		||||
      check-latest: true
 | 
			
		||||
  - run: python my_script.py
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
# Caching packages dependencies
 | 
			
		||||
 | 
			
		||||
The action has built-in functionality for caching and restoring dependencies. It uses [actions/cache](https://github.com/actions/toolkit/tree/main/packages/cache) under the hood for caching dependencies but requires less configuration settings. Supported package managers are `pip`, `pipenv` and `poetry`. The `cache` input is optional, and caching is turned off by default.
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,6 @@ import * as finder from '../src/find-pypy';
 | 
			
		||||
import {
 | 
			
		||||
  IPyPyManifestRelease,
 | 
			
		||||
  IS_WINDOWS,
 | 
			
		||||
  validateVersion,
 | 
			
		||||
  getPyPyVersionFromPath
 | 
			
		||||
} from '../src/utils';
 | 
			
		||||
 | 
			
		||||
@ -82,6 +81,12 @@ describe('findPyPyToolCache', () => {
 | 
			
		||||
  const pypyPath = path.join('PyPy', actualPythonVersion, architecture);
 | 
			
		||||
  let tcFind: jest.SpyInstance;
 | 
			
		||||
  let spyReadExactPyPyVersion: jest.SpyInstance;
 | 
			
		||||
  let infoSpy: jest.SpyInstance;
 | 
			
		||||
  let warningSpy: jest.SpyInstance;
 | 
			
		||||
  let debugSpy: jest.SpyInstance;
 | 
			
		||||
  let addPathSpy: jest.SpyInstance;
 | 
			
		||||
  let exportVariableSpy: jest.SpyInstance;
 | 
			
		||||
  let setOutputSpy: jest.SpyInstance;
 | 
			
		||||
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    tcFind = jest.spyOn(tc, 'find');
 | 
			
		||||
@ -94,6 +99,24 @@ describe('findPyPyToolCache', () => {
 | 
			
		||||
 | 
			
		||||
    spyReadExactPyPyVersion = jest.spyOn(utils, 'readExactPyPyVersionFile');
 | 
			
		||||
    spyReadExactPyPyVersion.mockImplementation(() => actualPyPyVersion);
 | 
			
		||||
 | 
			
		||||
    infoSpy = jest.spyOn(core, 'info');
 | 
			
		||||
    infoSpy.mockImplementation(() => null);
 | 
			
		||||
 | 
			
		||||
    warningSpy = jest.spyOn(core, 'warning');
 | 
			
		||||
    warningSpy.mockImplementation(() => null);
 | 
			
		||||
 | 
			
		||||
    debugSpy = jest.spyOn(core, 'debug');
 | 
			
		||||
    debugSpy.mockImplementation(() => null);
 | 
			
		||||
 | 
			
		||||
    addPathSpy = jest.spyOn(core, 'addPath');
 | 
			
		||||
    addPathSpy.mockImplementation(() => null);
 | 
			
		||||
 | 
			
		||||
    exportVariableSpy = jest.spyOn(core, 'exportVariable');
 | 
			
		||||
    exportVariableSpy.mockImplementation(() => null);
 | 
			
		||||
 | 
			
		||||
    setOutputSpy = jest.spyOn(core, 'setOutput');
 | 
			
		||||
    setOutputSpy.mockImplementation(() => null);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  afterEach(() => {
 | 
			
		||||
@ -136,6 +159,13 @@ describe('findPyPyToolCache', () => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
describe('findPyPyVersion', () => {
 | 
			
		||||
  let getBooleanInputSpy: jest.SpyInstance;
 | 
			
		||||
  let warningSpy: jest.SpyInstance;
 | 
			
		||||
  let debugSpy: jest.SpyInstance;
 | 
			
		||||
  let infoSpy: jest.SpyInstance;
 | 
			
		||||
  let addPathSpy: jest.SpyInstance;
 | 
			
		||||
  let exportVariableSpy: jest.SpyInstance;
 | 
			
		||||
  let setOutputSpy: jest.SpyInstance;
 | 
			
		||||
  let tcFind: jest.SpyInstance;
 | 
			
		||||
  let spyExtractZip: jest.SpyInstance;
 | 
			
		||||
  let spyExtractTar: jest.SpyInstance;
 | 
			
		||||
@ -154,6 +184,27 @@ describe('findPyPyVersion', () => {
 | 
			
		||||
  const env = process.env;
 | 
			
		||||
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    getBooleanInputSpy = jest.spyOn(core, 'getBooleanInput');
 | 
			
		||||
    getBooleanInputSpy.mockImplementation(() => false);
 | 
			
		||||
 | 
			
		||||
    infoSpy = jest.spyOn(core, 'info');
 | 
			
		||||
    infoSpy.mockImplementation(() => {});
 | 
			
		||||
 | 
			
		||||
    warningSpy = jest.spyOn(core, 'warning');
 | 
			
		||||
    warningSpy.mockImplementation(() => null);
 | 
			
		||||
 | 
			
		||||
    debugSpy = jest.spyOn(core, 'debug');
 | 
			
		||||
    debugSpy.mockImplementation(() => null);
 | 
			
		||||
 | 
			
		||||
    addPathSpy = jest.spyOn(core, 'addPath');
 | 
			
		||||
    addPathSpy.mockImplementation(() => null);
 | 
			
		||||
 | 
			
		||||
    exportVariableSpy = jest.spyOn(core, 'exportVariable');
 | 
			
		||||
    exportVariableSpy.mockImplementation(() => null);
 | 
			
		||||
 | 
			
		||||
    setOutputSpy = jest.spyOn(core, 'setOutput');
 | 
			
		||||
    setOutputSpy.mockImplementation(() => null);
 | 
			
		||||
 | 
			
		||||
    jest.resetModules();
 | 
			
		||||
    process.env = {...env};
 | 
			
		||||
    tcFind = jest.spyOn(tc, 'find');
 | 
			
		||||
@ -222,7 +273,7 @@ describe('findPyPyVersion', () => {
 | 
			
		||||
 | 
			
		||||
  it('found PyPy in toolcache', async () => {
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findPyPyVersion('pypy-3.6-v7.3.x', architecture, true)
 | 
			
		||||
      finder.findPyPyVersion('pypy-3.6-v7.3.x', architecture, true, false)
 | 
			
		||||
    ).resolves.toEqual({
 | 
			
		||||
      resolvedPythonVersion: '3.6.12',
 | 
			
		||||
      resolvedPyPyVersion: '7.3.3'
 | 
			
		||||
@ -240,13 +291,13 @@ describe('findPyPyVersion', () => {
 | 
			
		||||
 | 
			
		||||
  it('throw on invalid input format', async () => {
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, true)
 | 
			
		||||
      finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, true, false)
 | 
			
		||||
    ).rejects.toThrow();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('throw on invalid input format pypy3.7-7.3.x', async () => {
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, true)
 | 
			
		||||
      finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, true, false)
 | 
			
		||||
    ).rejects.toThrow();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
@ -258,7 +309,7 @@ describe('findPyPyVersion', () => {
 | 
			
		||||
    spyChmodSync = jest.spyOn(fs, 'chmodSync');
 | 
			
		||||
    spyChmodSync.mockImplementation(() => undefined);
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, true)
 | 
			
		||||
      finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, true, false)
 | 
			
		||||
    ).resolves.toEqual({
 | 
			
		||||
      resolvedPythonVersion: '3.7.9',
 | 
			
		||||
      resolvedPyPyVersion: '7.3.3'
 | 
			
		||||
@ -282,7 +333,7 @@ describe('findPyPyVersion', () => {
 | 
			
		||||
    spyChmodSync = jest.spyOn(fs, 'chmodSync');
 | 
			
		||||
    spyChmodSync.mockImplementation(() => undefined);
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, false)
 | 
			
		||||
      finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, false, false)
 | 
			
		||||
    ).resolves.toEqual({
 | 
			
		||||
      resolvedPythonVersion: '3.7.9',
 | 
			
		||||
      resolvedPyPyVersion: '7.3.3'
 | 
			
		||||
@ -293,9 +344,61 @@ describe('findPyPyVersion', () => {
 | 
			
		||||
 | 
			
		||||
  it('throw if release is not found', async () => {
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findPyPyVersion('pypy-3.7-v7.5.x', architecture, true)
 | 
			
		||||
      finder.findPyPyVersion('pypy-3.7-v7.5.x', architecture, true, false)
 | 
			
		||||
    ).rejects.toThrowError(
 | 
			
		||||
      `PyPy version 3.7 (v7.5.x) with arch ${architecture} not found`
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('check-latest enabled version found and used from toolcache', async () => {
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findPyPyVersion('pypy-3.6-v7.3.x', architecture, false, true)
 | 
			
		||||
    ).resolves.toEqual({
 | 
			
		||||
      resolvedPythonVersion: '3.6.12',
 | 
			
		||||
      resolvedPyPyVersion: '7.3.3'
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    expect(infoSpy).toHaveBeenCalledWith(
 | 
			
		||||
      'Resolved as PyPy 7.3.3 with Python (3.6.12)'
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('check-latest enabled version found and install successfully', async () => {
 | 
			
		||||
    spyCacheDir = jest.spyOn(tc, 'cacheDir');
 | 
			
		||||
    spyCacheDir.mockImplementation(() =>
 | 
			
		||||
      path.join(toolDir, 'PyPy', '3.7.7', architecture)
 | 
			
		||||
    );
 | 
			
		||||
    spyChmodSync = jest.spyOn(fs, 'chmodSync');
 | 
			
		||||
    spyChmodSync.mockImplementation(() => undefined);
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, false, true)
 | 
			
		||||
    ).resolves.toEqual({
 | 
			
		||||
      resolvedPythonVersion: '3.7.9',
 | 
			
		||||
      resolvedPyPyVersion: '7.3.3'
 | 
			
		||||
    });
 | 
			
		||||
    expect(infoSpy).toHaveBeenCalledWith(
 | 
			
		||||
      'Resolved as PyPy 7.3.3 with Python (3.7.9)'
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('check-latest enabled version is not found and used from toolcache', async () => {
 | 
			
		||||
    tcFind.mockImplementationOnce((tool: string, version: string) => {
 | 
			
		||||
      const semverRange = new semver.Range(version);
 | 
			
		||||
      let pypyPath = '';
 | 
			
		||||
      if (semver.satisfies('3.8.8', semverRange)) {
 | 
			
		||||
        pypyPath = path.join(toolDir, 'PyPy', '3.8.8', architecture);
 | 
			
		||||
      }
 | 
			
		||||
      return pypyPath;
 | 
			
		||||
    });
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findPyPyVersion('pypy-3.8-v7.3.x', architecture, false, true)
 | 
			
		||||
    ).resolves.toEqual({
 | 
			
		||||
      resolvedPythonVersion: '3.8.8',
 | 
			
		||||
      resolvedPyPyVersion: '7.3.3'
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    expect(infoSpy).toHaveBeenCalledWith(
 | 
			
		||||
      'Failed to resolve PyPy v7.3.x with Python (3.8) from manifest'
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
import io = require('@actions/io');
 | 
			
		||||
import fs = require('fs');
 | 
			
		||||
import path = require('path');
 | 
			
		||||
import * as io from '@actions/io';
 | 
			
		||||
import os from 'os';
 | 
			
		||||
import fs from 'fs';
 | 
			
		||||
import path from 'path';
 | 
			
		||||
 | 
			
		||||
const toolDir = path.join(
 | 
			
		||||
  __dirname,
 | 
			
		||||
@ -26,11 +27,14 @@ import * as installer from '../src/install-python';
 | 
			
		||||
const manifestData = require('./data/versions-manifest.json');
 | 
			
		||||
 | 
			
		||||
describe('Finder tests', () => {
 | 
			
		||||
  let writeSpy: jest.SpyInstance;
 | 
			
		||||
  let spyCoreAddPath: jest.SpyInstance;
 | 
			
		||||
  let spyCoreExportVariable: jest.SpyInstance;
 | 
			
		||||
  const env = process.env;
 | 
			
		||||
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    writeSpy = jest.spyOn(process.stdout, 'write');
 | 
			
		||||
    writeSpy.mockImplementation(() => {});
 | 
			
		||||
    jest.resetModules();
 | 
			
		||||
    process.env = {...env};
 | 
			
		||||
    spyCoreAddPath = jest.spyOn(core, 'addPath');
 | 
			
		||||
@ -45,11 +49,14 @@ describe('Finder tests', () => {
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Finds Python if it is installed', async () => {
 | 
			
		||||
    const getBooleanInputSpy = jest.spyOn(core, 'getBooleanInput');
 | 
			
		||||
    getBooleanInputSpy.mockImplementation(input => false);
 | 
			
		||||
 | 
			
		||||
    const pythonDir: string = path.join(toolDir, 'Python', '3.0.0', 'x64');
 | 
			
		||||
    await io.mkdirP(pythonDir);
 | 
			
		||||
    fs.writeFileSync(`${pythonDir}.complete`, 'hello');
 | 
			
		||||
    // This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
 | 
			
		||||
    await finder.useCpythonVersion('3.x', 'x64', true);
 | 
			
		||||
    await finder.useCpythonVersion('3.x', 'x64', true, false);
 | 
			
		||||
    expect(spyCoreAddPath).toHaveBeenCalled();
 | 
			
		||||
    expect(spyCoreExportVariable).toHaveBeenCalledWith(
 | 
			
		||||
      'pythonLocation',
 | 
			
		||||
@ -66,7 +73,7 @@ describe('Finder tests', () => {
 | 
			
		||||
    await io.mkdirP(pythonDir);
 | 
			
		||||
    fs.writeFileSync(`${pythonDir}.complete`, 'hello');
 | 
			
		||||
    // This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
 | 
			
		||||
    await finder.useCpythonVersion('3.x', 'x64', false);
 | 
			
		||||
    await finder.useCpythonVersion('3.x', 'x64', false, false);
 | 
			
		||||
    expect(spyCoreAddPath).not.toHaveBeenCalled();
 | 
			
		||||
    expect(spyCoreExportVariable).not.toHaveBeenCalled();
 | 
			
		||||
  });
 | 
			
		||||
@ -75,6 +82,9 @@ describe('Finder tests', () => {
 | 
			
		||||
    const findSpy: jest.SpyInstance = jest.spyOn(tc, 'getManifestFromRepo');
 | 
			
		||||
    findSpy.mockImplementation(() => <tc.IToolRelease[]>manifestData);
 | 
			
		||||
 | 
			
		||||
    const getBooleanInputSpy = jest.spyOn(core, 'getBooleanInput');
 | 
			
		||||
    getBooleanInputSpy.mockImplementation(input => false);
 | 
			
		||||
 | 
			
		||||
    const installSpy: jest.SpyInstance = jest.spyOn(
 | 
			
		||||
      installer,
 | 
			
		||||
      'installCpythonFromRelease'
 | 
			
		||||
@ -85,7 +95,7 @@ describe('Finder tests', () => {
 | 
			
		||||
      fs.writeFileSync(`${pythonDir}.complete`, 'hello');
 | 
			
		||||
    });
 | 
			
		||||
    // This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
 | 
			
		||||
    await finder.useCpythonVersion('1.2.3', 'x64', true);
 | 
			
		||||
    await finder.useCpythonVersion('1.2.3', 'x64', true, false);
 | 
			
		||||
    expect(spyCoreAddPath).toHaveBeenCalled();
 | 
			
		||||
    expect(spyCoreExportVariable).toHaveBeenCalledWith(
 | 
			
		||||
      'pythonLocation',
 | 
			
		||||
@ -101,6 +111,9 @@ describe('Finder tests', () => {
 | 
			
		||||
    const findSpy: jest.SpyInstance = jest.spyOn(tc, 'getManifestFromRepo');
 | 
			
		||||
    findSpy.mockImplementation(() => <tc.IToolRelease[]>manifestData);
 | 
			
		||||
 | 
			
		||||
    const getBooleanInputSpy = jest.spyOn(core, 'getBooleanInput');
 | 
			
		||||
    getBooleanInputSpy.mockImplementation(input => false);
 | 
			
		||||
 | 
			
		||||
    const installSpy: jest.SpyInstance = jest.spyOn(
 | 
			
		||||
      installer,
 | 
			
		||||
      'installCpythonFromRelease'
 | 
			
		||||
@ -116,7 +129,65 @@ describe('Finder tests', () => {
 | 
			
		||||
      fs.writeFileSync(`${pythonDir}.complete`, 'hello');
 | 
			
		||||
    });
 | 
			
		||||
    // This will throw if it doesn't find it in the manifest (because no such version exists)
 | 
			
		||||
    await finder.useCpythonVersion('1.2.3-beta.2', 'x64', true);
 | 
			
		||||
    await finder.useCpythonVersion('1.2.3-beta.2', 'x64', false, false);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Check-latest true, finds the latest version in the manifest', async () => {
 | 
			
		||||
    const findSpy: jest.SpyInstance = jest.spyOn(tc, 'getManifestFromRepo');
 | 
			
		||||
    findSpy.mockImplementation(() => <tc.IToolRelease[]>manifestData);
 | 
			
		||||
 | 
			
		||||
    const getBooleanInputSpy = jest.spyOn(core, 'getBooleanInput');
 | 
			
		||||
    getBooleanInputSpy.mockImplementation(input => true);
 | 
			
		||||
 | 
			
		||||
    const cnSpy: jest.SpyInstance = jest.spyOn(process.stdout, 'write');
 | 
			
		||||
    cnSpy.mockImplementation(line => {
 | 
			
		||||
      // uncomment to debug
 | 
			
		||||
      // process.stderr.write('write:' + line + '\n');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const addPathSpy: jest.SpyInstance = jest.spyOn(core, 'addPath');
 | 
			
		||||
    addPathSpy.mockImplementation(() => null);
 | 
			
		||||
 | 
			
		||||
    const infoSpy: jest.SpyInstance = jest.spyOn(core, 'info');
 | 
			
		||||
    infoSpy.mockImplementation(() => {});
 | 
			
		||||
 | 
			
		||||
    const debugSpy: jest.SpyInstance = jest.spyOn(core, 'debug');
 | 
			
		||||
    debugSpy.mockImplementation(() => {});
 | 
			
		||||
 | 
			
		||||
    const pythonDir: string = path.join(toolDir, 'Python', '1.2.2', 'x64');
 | 
			
		||||
    const expPath: string = path.join(toolDir, 'Python', '1.2.3', 'x64');
 | 
			
		||||
 | 
			
		||||
    const installSpy: jest.SpyInstance = jest.spyOn(
 | 
			
		||||
      installer,
 | 
			
		||||
      'installCpythonFromRelease'
 | 
			
		||||
    );
 | 
			
		||||
    installSpy.mockImplementation(async () => {
 | 
			
		||||
      await io.mkdirP(expPath);
 | 
			
		||||
      fs.writeFileSync(`${expPath}.complete`, 'hello');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const tcFindSpy: jest.SpyInstance = jest.spyOn(tc, 'find');
 | 
			
		||||
    tcFindSpy
 | 
			
		||||
      .mockImplementationOnce(() => '')
 | 
			
		||||
      .mockImplementationOnce(() => expPath);
 | 
			
		||||
 | 
			
		||||
    await io.mkdirP(pythonDir);
 | 
			
		||||
    await io.rmRF(path.join(toolDir, 'Python', '1.2.3'));
 | 
			
		||||
 | 
			
		||||
    fs.writeFileSync(`${pythonDir}.complete`, 'hello');
 | 
			
		||||
    // This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
 | 
			
		||||
    await finder.useCpythonVersion('1.2', 'x64', true, true);
 | 
			
		||||
 | 
			
		||||
    expect(infoSpy).toHaveBeenCalledWith("Resolved as '1.2.3'");
 | 
			
		||||
    expect(infoSpy).toHaveBeenCalledWith(
 | 
			
		||||
      'Version 1.2.3 was not found in the local cache'
 | 
			
		||||
    );
 | 
			
		||||
    expect(infoSpy).toBeCalledWith(
 | 
			
		||||
      'Version 1.2.3 is available for downloading'
 | 
			
		||||
    );
 | 
			
		||||
    expect(installSpy).toHaveBeenCalled();
 | 
			
		||||
    expect(addPathSpy).toHaveBeenCalledWith(expPath);
 | 
			
		||||
    await finder.useCpythonVersion('1.2.3-beta.2', 'x64', false, true);
 | 
			
		||||
    expect(spyCoreAddPath).toHaveBeenCalled();
 | 
			
		||||
    expect(spyCoreExportVariable).toHaveBeenCalledWith(
 | 
			
		||||
      'pythonLocation',
 | 
			
		||||
@ -132,7 +203,7 @@ describe('Finder tests', () => {
 | 
			
		||||
    // This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
 | 
			
		||||
    let thrown = false;
 | 
			
		||||
    try {
 | 
			
		||||
      await finder.useCpythonVersion('3.300000', 'x64', true);
 | 
			
		||||
      await finder.useCpythonVersion('3.300000', 'x64', true, false);
 | 
			
		||||
    } catch {
 | 
			
		||||
      thrown = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ import {HttpClient} from '@actions/http-client';
 | 
			
		||||
import * as ifm from '@actions/http-client/interfaces';
 | 
			
		||||
import * as tc from '@actions/tool-cache';
 | 
			
		||||
import * as exec from '@actions/exec';
 | 
			
		||||
import * as core from '@actions/core';
 | 
			
		||||
import * as path from 'path';
 | 
			
		||||
 | 
			
		||||
import * as installer from '../src/install-pypy';
 | 
			
		||||
@ -51,6 +52,22 @@ describe('findRelease', () => {
 | 
			
		||||
    download_url: `https://test.download.python.org/pypy/pypy3.6-v7.3.3-${extensionName}`
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  let getBooleanInputSpy: jest.SpyInstance;
 | 
			
		||||
  let warningSpy: jest.SpyInstance;
 | 
			
		||||
  let debugSpy: jest.SpyInstance;
 | 
			
		||||
  let infoSpy: jest.SpyInstance;
 | 
			
		||||
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    infoSpy = jest.spyOn(core, 'info');
 | 
			
		||||
    infoSpy.mockImplementation(() => {});
 | 
			
		||||
 | 
			
		||||
    warningSpy = jest.spyOn(core, 'warning');
 | 
			
		||||
    warningSpy.mockImplementation(() => null);
 | 
			
		||||
 | 
			
		||||
    debugSpy = jest.spyOn(core, 'debug');
 | 
			
		||||
    debugSpy.mockImplementation(() => null);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it("Python version is found, but PyPy version doesn't match", () => {
 | 
			
		||||
    const pythonVersion = '3.6';
 | 
			
		||||
    const pypyVersion = '7.3.7';
 | 
			
		||||
@ -133,6 +150,10 @@ describe('findRelease', () => {
 | 
			
		||||
 | 
			
		||||
describe('installPyPy', () => {
 | 
			
		||||
  let tcFind: jest.SpyInstance;
 | 
			
		||||
  let getBooleanInputSpy: jest.SpyInstance;
 | 
			
		||||
  let warningSpy: jest.SpyInstance;
 | 
			
		||||
  let debugSpy: jest.SpyInstance;
 | 
			
		||||
  let infoSpy: jest.SpyInstance;
 | 
			
		||||
  let spyExtractZip: jest.SpyInstance;
 | 
			
		||||
  let spyExtractTar: jest.SpyInstance;
 | 
			
		||||
  let spyFsReadDir: jest.SpyInstance;
 | 
			
		||||
@ -158,6 +179,15 @@ describe('installPyPy', () => {
 | 
			
		||||
    spyExtractTar = jest.spyOn(tc, 'extractTar');
 | 
			
		||||
    spyExtractTar.mockImplementation(() => tempDir);
 | 
			
		||||
 | 
			
		||||
    infoSpy = jest.spyOn(core, 'info');
 | 
			
		||||
    infoSpy.mockImplementation(() => {});
 | 
			
		||||
 | 
			
		||||
    warningSpy = jest.spyOn(core, 'warning');
 | 
			
		||||
    warningSpy.mockImplementation(() => null);
 | 
			
		||||
 | 
			
		||||
    debugSpy = jest.spyOn(core, 'debug');
 | 
			
		||||
    debugSpy.mockImplementation(() => null);
 | 
			
		||||
 | 
			
		||||
    spyFsReadDir = jest.spyOn(fs, 'readdirSync');
 | 
			
		||||
    spyFsReadDir.mockImplementation(() => ['PyPyTest']);
 | 
			
		||||
 | 
			
		||||
@ -194,7 +224,7 @@ describe('installPyPy', () => {
 | 
			
		||||
 | 
			
		||||
  it('throw if release is not found', async () => {
 | 
			
		||||
    await expect(
 | 
			
		||||
      installer.installPyPy('7.3.3', '3.6.17', architecture)
 | 
			
		||||
      installer.installPyPy('7.3.3', '3.6.17', architecture, undefined)
 | 
			
		||||
    ).rejects.toThrowError(
 | 
			
		||||
      `PyPy version 3.6.17 (7.3.3) with arch ${architecture} not found`
 | 
			
		||||
    );
 | 
			
		||||
@ -214,7 +244,7 @@ describe('installPyPy', () => {
 | 
			
		||||
    spyChmodSync.mockImplementation(() => undefined);
 | 
			
		||||
 | 
			
		||||
    await expect(
 | 
			
		||||
      installer.installPyPy('7.3.x', '3.6.12', architecture)
 | 
			
		||||
      installer.installPyPy('7.3.x', '3.6.12', architecture, undefined)
 | 
			
		||||
    ).resolves.toEqual({
 | 
			
		||||
      installDir: path.join(toolDir, 'PyPy', '3.6.12', architecture),
 | 
			
		||||
      resolvedPythonVersion: '3.6.12',
 | 
			
		||||
 | 
			
		||||
@ -12,6 +12,9 @@ inputs:
 | 
			
		||||
    required: false
 | 
			
		||||
  architecture:
 | 
			
		||||
    description: 'The target architecture (x86, x64) of the Python interpreter.'
 | 
			
		||||
  check-latest:
 | 
			
		||||
    description: 'Set this option if you want the action to check for the latest available version that satisfies the version spec.'
 | 
			
		||||
    default: 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.
 | 
			
		||||
    default: ${{ github.token }}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										66
									
								
								dist/setup/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										66
									
								
								dist/setup/index.js
									
									
									
									
										vendored
									
									
								
							@ -64685,19 +64685,34 @@ const utils_1 = __nccwpck_require__(1314);
 | 
			
		||||
const semver = __importStar(__nccwpck_require__(1383));
 | 
			
		||||
const core = __importStar(__nccwpck_require__(2186));
 | 
			
		||||
const tc = __importStar(__nccwpck_require__(7784));
 | 
			
		||||
function findPyPyVersion(versionSpec, architecture, updateEnvironment) {
 | 
			
		||||
function findPyPyVersion(versionSpec, architecture, updateEnvironment, checkLatest) {
 | 
			
		||||
    return __awaiter(this, void 0, void 0, function* () {
 | 
			
		||||
        let resolvedPyPyVersion = '';
 | 
			
		||||
        let resolvedPythonVersion = '';
 | 
			
		||||
        let installDir;
 | 
			
		||||
        let releases;
 | 
			
		||||
        const pypyVersionSpec = parsePyPyVersion(versionSpec);
 | 
			
		||||
        if (checkLatest) {
 | 
			
		||||
            releases = yield pypyInstall.getAvailablePyPyVersions();
 | 
			
		||||
            if (releases && releases.length > 0) {
 | 
			
		||||
                const releaseData = pypyInstall.findRelease(releases, pypyVersionSpec.pythonVersion, pypyVersionSpec.pypyVersion, architecture);
 | 
			
		||||
                if (releaseData) {
 | 
			
		||||
                    core.info(`Resolved as PyPy ${releaseData.resolvedPyPyVersion} with Python (${releaseData.resolvedPythonVersion})`);
 | 
			
		||||
                    pypyVersionSpec.pythonVersion = releaseData.resolvedPythonVersion;
 | 
			
		||||
                    pypyVersionSpec.pypyVersion = releaseData.resolvedPyPyVersion;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    core.info(`Failed to resolve PyPy ${pypyVersionSpec.pypyVersion} with Python (${pypyVersionSpec.pythonVersion}) from manifest`);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        ({ installDir, resolvedPythonVersion, resolvedPyPyVersion } = findPyPyToolCache(pypyVersionSpec.pythonVersion, pypyVersionSpec.pypyVersion, architecture));
 | 
			
		||||
        if (!installDir) {
 | 
			
		||||
            ({
 | 
			
		||||
                installDir,
 | 
			
		||||
                resolvedPythonVersion,
 | 
			
		||||
                resolvedPyPyVersion
 | 
			
		||||
            } = yield pypyInstall.installPyPy(pypyVersionSpec.pypyVersion, pypyVersionSpec.pythonVersion, architecture));
 | 
			
		||||
            } = yield pypyInstall.installPyPy(pypyVersionSpec.pypyVersion, pypyVersionSpec.pythonVersion, architecture, releases));
 | 
			
		||||
        }
 | 
			
		||||
        const pipDir = utils_1.IS_WINDOWS ? 'Scripts' : 'bin';
 | 
			
		||||
        const _binDir = path.join(installDir, pipDir);
 | 
			
		||||
@ -64847,15 +64862,28 @@ function binDir(installDir) {
 | 
			
		||||
        return path.join(installDir, 'bin');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
function useCpythonVersion(version, architecture, updateEnvironment) {
 | 
			
		||||
function useCpythonVersion(version, architecture, updateEnvironment, checkLatest) {
 | 
			
		||||
    var _a;
 | 
			
		||||
    return __awaiter(this, void 0, void 0, function* () {
 | 
			
		||||
        let manifest = null;
 | 
			
		||||
        const desugaredVersionSpec = desugarDevVersion(version);
 | 
			
		||||
        const semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec);
 | 
			
		||||
        let semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec);
 | 
			
		||||
        core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`);
 | 
			
		||||
        if (checkLatest) {
 | 
			
		||||
            manifest = yield installer.getManifest();
 | 
			
		||||
            const resolvedVersion = (_a = (yield installer.findReleaseFromManifest(semanticVersionSpec, architecture, manifest))) === null || _a === void 0 ? void 0 : _a.version;
 | 
			
		||||
            if (resolvedVersion) {
 | 
			
		||||
                semanticVersionSpec = resolvedVersion;
 | 
			
		||||
                core.info(`Resolved as '${semanticVersionSpec}'`);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                core.info(`Failed to resolve version ${semanticVersionSpec} from manifest`);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        let installDir = tc.find('Python', semanticVersionSpec, architecture);
 | 
			
		||||
        if (!installDir) {
 | 
			
		||||
            core.info(`Version ${semanticVersionSpec} was not found in the local cache`);
 | 
			
		||||
            const foundRelease = yield installer.findReleaseFromManifest(semanticVersionSpec, architecture);
 | 
			
		||||
            const foundRelease = yield installer.findReleaseFromManifest(semanticVersionSpec, architecture, manifest);
 | 
			
		||||
            if (foundRelease && foundRelease.files && foundRelease.files.length > 0) {
 | 
			
		||||
                core.info(`Version ${semanticVersionSpec} is available for downloading`);
 | 
			
		||||
                yield installer.installCpythonFromRelease(foundRelease);
 | 
			
		||||
@ -64974,7 +65002,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
 | 
			
		||||
    return (mod && mod.__esModule) ? mod : { "default": mod };
 | 
			
		||||
};
 | 
			
		||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
 | 
			
		||||
exports.findAssetForMacOrLinux = exports.findAssetForWindows = exports.isArchPresentForMacOrLinux = exports.isArchPresentForWindows = exports.pypyVersionToSemantic = exports.getPyPyBinaryPath = exports.findRelease = exports.installPyPy = void 0;
 | 
			
		||||
exports.findAssetForMacOrLinux = exports.findAssetForWindows = exports.isArchPresentForMacOrLinux = exports.isArchPresentForWindows = exports.pypyVersionToSemantic = exports.getPyPyBinaryPath = exports.findRelease = exports.getAvailablePyPyVersions = exports.installPyPy = void 0;
 | 
			
		||||
const path = __importStar(__nccwpck_require__(1017));
 | 
			
		||||
const core = __importStar(__nccwpck_require__(2186));
 | 
			
		||||
const tc = __importStar(__nccwpck_require__(7784));
 | 
			
		||||
@ -64983,10 +65011,10 @@ const httpm = __importStar(__nccwpck_require__(9925));
 | 
			
		||||
const exec = __importStar(__nccwpck_require__(1514));
 | 
			
		||||
const fs_1 = __importDefault(__nccwpck_require__(7147));
 | 
			
		||||
const utils_1 = __nccwpck_require__(1314);
 | 
			
		||||
function installPyPy(pypyVersion, pythonVersion, architecture) {
 | 
			
		||||
function installPyPy(pypyVersion, pythonVersion, architecture, releases) {
 | 
			
		||||
    return __awaiter(this, void 0, void 0, function* () {
 | 
			
		||||
        let downloadDir;
 | 
			
		||||
        const releases = yield getAvailablePyPyVersions();
 | 
			
		||||
        releases = releases !== null && releases !== void 0 ? releases : (yield getAvailablePyPyVersions());
 | 
			
		||||
        if (!releases || releases.length === 0) {
 | 
			
		||||
            throw new Error('No release was found in PyPy version.json');
 | 
			
		||||
        }
 | 
			
		||||
@ -65032,6 +65060,7 @@ function getAvailablePyPyVersions() {
 | 
			
		||||
        return response.result;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
exports.getAvailablePyPyVersions = getAvailablePyPyVersions;
 | 
			
		||||
function createPyPySymlink(pypyBinaryPath, pythonVersion) {
 | 
			
		||||
    return __awaiter(this, void 0, void 0, function* () {
 | 
			
		||||
        const version = semver.coerce(pythonVersion);
 | 
			
		||||
@ -65154,7 +65183,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
 | 
			
		||||
exports.installCpythonFromRelease = exports.findReleaseFromManifest = exports.MANIFEST_URL = void 0;
 | 
			
		||||
exports.installCpythonFromRelease = exports.getManifest = exports.findReleaseFromManifest = exports.MANIFEST_URL = void 0;
 | 
			
		||||
const path = __importStar(__nccwpck_require__(1017));
 | 
			
		||||
const core = __importStar(__nccwpck_require__(2186));
 | 
			
		||||
const tc = __importStar(__nccwpck_require__(7784));
 | 
			
		||||
@ -65166,13 +65195,21 @@ const MANIFEST_REPO_OWNER = 'actions';
 | 
			
		||||
const MANIFEST_REPO_NAME = 'python-versions';
 | 
			
		||||
const MANIFEST_REPO_BRANCH = 'main';
 | 
			
		||||
exports.MANIFEST_URL = `https://raw.githubusercontent.com/${MANIFEST_REPO_OWNER}/${MANIFEST_REPO_NAME}/${MANIFEST_REPO_BRANCH}/versions-manifest.json`;
 | 
			
		||||
function findReleaseFromManifest(semanticVersionSpec, architecture) {
 | 
			
		||||
function findReleaseFromManifest(semanticVersionSpec, architecture, manifest) {
 | 
			
		||||
    return __awaiter(this, void 0, void 0, function* () {
 | 
			
		||||
        const manifest = yield tc.getManifestFromRepo(MANIFEST_REPO_OWNER, MANIFEST_REPO_NAME, AUTH, MANIFEST_REPO_BRANCH);
 | 
			
		||||
        return yield tc.findFromManifest(semanticVersionSpec, false, manifest, architecture);
 | 
			
		||||
        if (!manifest) {
 | 
			
		||||
            manifest = yield getManifest();
 | 
			
		||||
        }
 | 
			
		||||
        const foundRelease = yield tc.findFromManifest(semanticVersionSpec, false, manifest, architecture);
 | 
			
		||||
        return foundRelease;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
exports.findReleaseFromManifest = findReleaseFromManifest;
 | 
			
		||||
function getManifest() {
 | 
			
		||||
    core.debug(`Getting manifest from ${MANIFEST_REPO_OWNER}/${MANIFEST_REPO_NAME}@${MANIFEST_REPO_BRANCH}`);
 | 
			
		||||
    return tc.getManifestFromRepo(MANIFEST_REPO_OWNER, MANIFEST_REPO_NAME, AUTH, MANIFEST_REPO_BRANCH);
 | 
			
		||||
}
 | 
			
		||||
exports.getManifest = getManifest;
 | 
			
		||||
function installPython(workingDirectory) {
 | 
			
		||||
    return __awaiter(this, void 0, void 0, function* () {
 | 
			
		||||
        const options = {
 | 
			
		||||
@ -65315,17 +65352,18 @@ function run() {
 | 
			
		||||
        core.debug(`Python is expected to be installed into RUNNER_TOOL_CACHE=${process.env['RUNNER_TOOL_CACHE']}`);
 | 
			
		||||
        try {
 | 
			
		||||
            const version = resolveVersionInput();
 | 
			
		||||
            const checkLatest = core.getBooleanInput('check-latest');
 | 
			
		||||
            if (version) {
 | 
			
		||||
                let pythonVersion;
 | 
			
		||||
                const arch = core.getInput('architecture') || os.arch();
 | 
			
		||||
                const updateEnvironment = core.getBooleanInput('update-environment');
 | 
			
		||||
                if (isPyPyVersion(version)) {
 | 
			
		||||
                    const installed = yield finderPyPy.findPyPyVersion(version, arch, updateEnvironment);
 | 
			
		||||
                    const installed = yield finderPyPy.findPyPyVersion(version, arch, updateEnvironment, checkLatest);
 | 
			
		||||
                    pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`;
 | 
			
		||||
                    core.info(`Successfully set up PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})`);
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    const installed = yield finder.useCpythonVersion(version, arch, updateEnvironment);
 | 
			
		||||
                    const installed = yield finder.useCpythonVersion(version, arch, updateEnvironment, checkLatest);
 | 
			
		||||
                    pythonVersion = installed.version;
 | 
			
		||||
                    core.info(`Successfully set up ${installed.impl} (${pythonVersion})`);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,8 @@ import {
 | 
			
		||||
  validateVersion,
 | 
			
		||||
  getPyPyVersionFromPath,
 | 
			
		||||
  readExactPyPyVersionFile,
 | 
			
		||||
  validatePythonVersionFormatForPyPy
 | 
			
		||||
  validatePythonVersionFormatForPyPy,
 | 
			
		||||
  IPyPyManifestRelease
 | 
			
		||||
} from './utils';
 | 
			
		||||
 | 
			
		||||
import * as semver from 'semver';
 | 
			
		||||
@ -21,14 +22,40 @@ interface IPyPyVersionSpec {
 | 
			
		||||
export async function findPyPyVersion(
 | 
			
		||||
  versionSpec: string,
 | 
			
		||||
  architecture: string,
 | 
			
		||||
  updateEnvironment: boolean
 | 
			
		||||
  updateEnvironment: boolean,
 | 
			
		||||
  checkLatest: boolean
 | 
			
		||||
): Promise<{resolvedPyPyVersion: string; resolvedPythonVersion: string}> {
 | 
			
		||||
  let resolvedPyPyVersion = '';
 | 
			
		||||
  let resolvedPythonVersion = '';
 | 
			
		||||
  let installDir: string | null;
 | 
			
		||||
  let releases: IPyPyManifestRelease[] | undefined;
 | 
			
		||||
 | 
			
		||||
  const pypyVersionSpec = parsePyPyVersion(versionSpec);
 | 
			
		||||
 | 
			
		||||
  if (checkLatest) {
 | 
			
		||||
    releases = await pypyInstall.getAvailablePyPyVersions();
 | 
			
		||||
    if (releases && releases.length > 0) {
 | 
			
		||||
      const releaseData = pypyInstall.findRelease(
 | 
			
		||||
        releases,
 | 
			
		||||
        pypyVersionSpec.pythonVersion,
 | 
			
		||||
        pypyVersionSpec.pypyVersion,
 | 
			
		||||
        architecture
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      if (releaseData) {
 | 
			
		||||
        core.info(
 | 
			
		||||
          `Resolved as PyPy ${releaseData.resolvedPyPyVersion} with Python (${releaseData.resolvedPythonVersion})`
 | 
			
		||||
        );
 | 
			
		||||
        pypyVersionSpec.pythonVersion = releaseData.resolvedPythonVersion;
 | 
			
		||||
        pypyVersionSpec.pypyVersion = releaseData.resolvedPyPyVersion;
 | 
			
		||||
      } else {
 | 
			
		||||
        core.info(
 | 
			
		||||
          `Failed to resolve PyPy ${pypyVersionSpec.pypyVersion} with Python (${pypyVersionSpec.pythonVersion}) from manifest`
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ({installDir, resolvedPythonVersion, resolvedPyPyVersion} = findPyPyToolCache(
 | 
			
		||||
    pypyVersionSpec.pythonVersion,
 | 
			
		||||
    pypyVersionSpec.pypyVersion,
 | 
			
		||||
@ -43,7 +70,8 @@ export async function findPyPyVersion(
 | 
			
		||||
    } = await pypyInstall.installPyPy(
 | 
			
		||||
      pypyVersionSpec.pypyVersion,
 | 
			
		||||
      pypyVersionSpec.pythonVersion,
 | 
			
		||||
      architecture
 | 
			
		||||
      architecture,
 | 
			
		||||
      releases
 | 
			
		||||
    ));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -33,12 +33,34 @@ function binDir(installDir: string): string {
 | 
			
		||||
export async function useCpythonVersion(
 | 
			
		||||
  version: string,
 | 
			
		||||
  architecture: string,
 | 
			
		||||
  updateEnvironment: boolean
 | 
			
		||||
  updateEnvironment: boolean,
 | 
			
		||||
  checkLatest: boolean
 | 
			
		||||
): Promise<InstalledVersion> {
 | 
			
		||||
  let manifest: tc.IToolRelease[] | null = null;
 | 
			
		||||
  const desugaredVersionSpec = desugarDevVersion(version);
 | 
			
		||||
  const semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec);
 | 
			
		||||
  let semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec);
 | 
			
		||||
  core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`);
 | 
			
		||||
 | 
			
		||||
  if (checkLatest) {
 | 
			
		||||
    manifest = await installer.getManifest();
 | 
			
		||||
    const resolvedVersion = (
 | 
			
		||||
      await installer.findReleaseFromManifest(
 | 
			
		||||
        semanticVersionSpec,
 | 
			
		||||
        architecture,
 | 
			
		||||
        manifest
 | 
			
		||||
      )
 | 
			
		||||
    )?.version;
 | 
			
		||||
 | 
			
		||||
    if (resolvedVersion) {
 | 
			
		||||
      semanticVersionSpec = resolvedVersion;
 | 
			
		||||
      core.info(`Resolved as '${semanticVersionSpec}'`);
 | 
			
		||||
    } else {
 | 
			
		||||
      core.info(
 | 
			
		||||
        `Failed to resolve version ${semanticVersionSpec} from manifest`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  let installDir: string | null = tc.find(
 | 
			
		||||
    'Python',
 | 
			
		||||
    semanticVersionSpec,
 | 
			
		||||
@ -50,7 +72,8 @@ export async function useCpythonVersion(
 | 
			
		||||
    );
 | 
			
		||||
    const foundRelease = await installer.findReleaseFromManifest(
 | 
			
		||||
      semanticVersionSpec,
 | 
			
		||||
      architecture
 | 
			
		||||
      architecture,
 | 
			
		||||
      manifest
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (foundRelease && foundRelease.files && foundRelease.files.length > 0) {
 | 
			
		||||
 | 
			
		||||
@ -19,11 +19,13 @@ import {
 | 
			
		||||
export async function installPyPy(
 | 
			
		||||
  pypyVersion: string,
 | 
			
		||||
  pythonVersion: string,
 | 
			
		||||
  architecture: string
 | 
			
		||||
  architecture: string,
 | 
			
		||||
  releases: IPyPyManifestRelease[] | undefined
 | 
			
		||||
) {
 | 
			
		||||
  let downloadDir;
 | 
			
		||||
 | 
			
		||||
  const releases = await getAvailablePyPyVersions();
 | 
			
		||||
  releases = releases ?? (await getAvailablePyPyVersions());
 | 
			
		||||
 | 
			
		||||
  if (!releases || releases.length === 0) {
 | 
			
		||||
    throw new Error('No release was found in PyPy version.json');
 | 
			
		||||
  }
 | 
			
		||||
@ -78,7 +80,7 @@ export async function installPyPy(
 | 
			
		||||
  return {installDir, resolvedPythonVersion, resolvedPyPyVersion};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function getAvailablePyPyVersions() {
 | 
			
		||||
export async function getAvailablePyPyVersions() {
 | 
			
		||||
  const url = 'https://downloads.python.org/pypy/versions.json';
 | 
			
		||||
  const http: httpm.HttpClient = new httpm.HttpClient('tool-cache');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -14,20 +14,33 @@ export const MANIFEST_URL = `https://raw.githubusercontent.com/${MANIFEST_REPO_O
 | 
			
		||||
 | 
			
		||||
export async function findReleaseFromManifest(
 | 
			
		||||
  semanticVersionSpec: string,
 | 
			
		||||
  architecture: string
 | 
			
		||||
  architecture: string,
 | 
			
		||||
  manifest: tc.IToolRelease[] | null
 | 
			
		||||
): Promise<tc.IToolRelease | undefined> {
 | 
			
		||||
  const manifest: tc.IToolRelease[] = await tc.getManifestFromRepo(
 | 
			
		||||
    MANIFEST_REPO_OWNER,
 | 
			
		||||
    MANIFEST_REPO_NAME,
 | 
			
		||||
    AUTH,
 | 
			
		||||
    MANIFEST_REPO_BRANCH
 | 
			
		||||
  );
 | 
			
		||||
  return await tc.findFromManifest(
 | 
			
		||||
  if (!manifest) {
 | 
			
		||||
    manifest = await getManifest();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const foundRelease = await tc.findFromManifest(
 | 
			
		||||
    semanticVersionSpec,
 | 
			
		||||
    false,
 | 
			
		||||
    manifest,
 | 
			
		||||
    architecture
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  return foundRelease;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getManifest(): Promise<tc.IToolRelease[]> {
 | 
			
		||||
  core.debug(
 | 
			
		||||
    `Getting manifest from ${MANIFEST_REPO_OWNER}/${MANIFEST_REPO_NAME}@${MANIFEST_REPO_BRANCH}`
 | 
			
		||||
  );
 | 
			
		||||
  return tc.getManifestFromRepo(
 | 
			
		||||
    MANIFEST_REPO_OWNER,
 | 
			
		||||
    MANIFEST_REPO_NAME,
 | 
			
		||||
    AUTH,
 | 
			
		||||
    MANIFEST_REPO_BRANCH
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function installPython(workingDirectory: string) {
 | 
			
		||||
 | 
			
		||||
@ -80,6 +80,8 @@ async function run() {
 | 
			
		||||
  );
 | 
			
		||||
  try {
 | 
			
		||||
    const version = resolveVersionInput();
 | 
			
		||||
    const checkLatest = core.getBooleanInput('check-latest');
 | 
			
		||||
 | 
			
		||||
    if (version) {
 | 
			
		||||
      let pythonVersion: string;
 | 
			
		||||
      const arch: string = core.getInput('architecture') || os.arch();
 | 
			
		||||
@ -88,7 +90,8 @@ async function run() {
 | 
			
		||||
        const installed = await finderPyPy.findPyPyVersion(
 | 
			
		||||
          version,
 | 
			
		||||
          arch,
 | 
			
		||||
          updateEnvironment
 | 
			
		||||
          updateEnvironment,
 | 
			
		||||
          checkLatest
 | 
			
		||||
        );
 | 
			
		||||
        pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`;
 | 
			
		||||
        core.info(
 | 
			
		||||
@ -98,7 +101,8 @@ async function run() {
 | 
			
		||||
        const installed = await finder.useCpythonVersion(
 | 
			
		||||
          version,
 | 
			
		||||
          arch,
 | 
			
		||||
          updateEnvironment
 | 
			
		||||
          updateEnvironment,
 | 
			
		||||
          checkLatest
 | 
			
		||||
        );
 | 
			
		||||
        pythonVersion = installed.version;
 | 
			
		||||
        core.info(`Successfully set up ${installed.impl} (${pythonVersion})`);
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user