mirror of
				https://kkgithub.com/actions/setup-python.git
				synced 2025-11-04 12:44:05 +08:00 
			
		
		
		
	Add GraalPy support (#694)
* Add support for graalpy * add graalpy test workflow * format, lint and build * symlink graalpy binaries names * fix macos names for graalpy * Don't attempt to update pip for graalpy * Remove test schedule * Extract common getBinaryDirectory function for PyPy and GraalPy * Clean up and format * Pass GitHub token to GraalPy queries * Utilize pagination when querying GraalPy GitHub releases * Build * Fix lint errors * Deal with possible multiple artifacts for a single releases * Skip few GraalPy tests on windows - we don't have a windows release yet * Fix GraalPy test on Mac OS * Build * Skip one more GraalPy test on windows --------- Co-authored-by: Michael Simacek <michael.simacek@oracle.com>
This commit is contained in:
		
							
								
								
									
										378
									
								
								__tests__/find-graalpy.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										378
									
								
								__tests__/find-graalpy.test.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,378 @@
 | 
			
		||||
import fs from 'fs';
 | 
			
		||||
 | 
			
		||||
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 semver from 'semver';
 | 
			
		||||
 | 
			
		||||
import * as finder from '../src/find-graalpy';
 | 
			
		||||
import {IGraalPyManifestRelease, IS_WINDOWS} from '../src/utils';
 | 
			
		||||
 | 
			
		||||
import manifestData from './data/graalpy.json';
 | 
			
		||||
 | 
			
		||||
const architecture = 'x64';
 | 
			
		||||
 | 
			
		||||
const toolDir = path.join(__dirname, 'runner', 'tools');
 | 
			
		||||
const tempDir = path.join(__dirname, 'runner', 'temp');
 | 
			
		||||
 | 
			
		||||
/* GraalPy doesn't have a windows release yet */
 | 
			
		||||
const describeSkipOnWindows = IS_WINDOWS ? describe.skip : describe;
 | 
			
		||||
 | 
			
		||||
describe('parseGraalPyVersion', () => {
 | 
			
		||||
  it.each([
 | 
			
		||||
    ['graalpy-23', '23'],
 | 
			
		||||
    ['graalpy-23.0', '23.0'],
 | 
			
		||||
    ['graalpy23.0', '23.0']
 | 
			
		||||
  ])('%s -> %s', (input, expected) => {
 | 
			
		||||
    expect(finder.parseGraalPyVersion(input)).toEqual(expected);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it.each(['', 'graalpy-', 'graalpy', 'p', 'notgraalpy-'])(
 | 
			
		||||
    'throw on invalid input "%s"',
 | 
			
		||||
    input => {
 | 
			
		||||
      expect(() => finder.parseGraalPyVersion(input)).toThrow(
 | 
			
		||||
        "Invalid 'version' property for GraalPy. GraalPy version should be specified as 'graalpy<python-version>' or 'graalpy-<python-version>'. See README for examples and documentation."
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
describe('findGraalPyToolCache', () => {
 | 
			
		||||
  const actualGraalPyVersion = '23.0.0';
 | 
			
		||||
  const graalpyPath = path.join('GraalPy', actualGraalPyVersion, architecture);
 | 
			
		||||
  let tcFind: 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');
 | 
			
		||||
    tcFind.mockImplementation((toolname: string, pythonVersion: string) => {
 | 
			
		||||
      const semverVersion = new semver.Range(pythonVersion);
 | 
			
		||||
      return semver.satisfies(actualGraalPyVersion, semverVersion)
 | 
			
		||||
        ? graalpyPath
 | 
			
		||||
        : '';
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    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(() => {
 | 
			
		||||
    jest.resetAllMocks();
 | 
			
		||||
    jest.clearAllMocks();
 | 
			
		||||
    jest.restoreAllMocks();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('GraalPy exists on the path and versions are satisfied', () => {
 | 
			
		||||
    expect(finder.findGraalPyToolCache('23.0.0', architecture)).toEqual({
 | 
			
		||||
      installDir: graalpyPath,
 | 
			
		||||
      resolvedGraalPyVersion: actualGraalPyVersion
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('GraalPy exists on the path and versions are satisfied with semver', () => {
 | 
			
		||||
    expect(finder.findGraalPyToolCache('23.0', architecture)).toEqual({
 | 
			
		||||
      installDir: graalpyPath,
 | 
			
		||||
      resolvedGraalPyVersion: actualGraalPyVersion
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it("GraalPy exists on the path, but version doesn't match", () => {
 | 
			
		||||
    expect(finder.findGraalPyToolCache('22.3', architecture)).toEqual({
 | 
			
		||||
      installDir: '',
 | 
			
		||||
      resolvedGraalPyVersion: ''
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
describeSkipOnWindows('findGraalPyVersion', () => {
 | 
			
		||||
  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;
 | 
			
		||||
  let spyHttpClient: jest.SpyInstance;
 | 
			
		||||
  let spyExistsSync: jest.SpyInstance;
 | 
			
		||||
  let spyExec: jest.SpyInstance;
 | 
			
		||||
  let spySymlinkSync: jest.SpyInstance;
 | 
			
		||||
  let spyDownloadTool: jest.SpyInstance;
 | 
			
		||||
  let spyFsReadDir: jest.SpyInstance;
 | 
			
		||||
  let spyCacheDir: jest.SpyInstance;
 | 
			
		||||
  let spyChmodSync: jest.SpyInstance;
 | 
			
		||||
  let spyCoreAddPath: jest.SpyInstance;
 | 
			
		||||
  let spyCoreExportVariable: jest.SpyInstance;
 | 
			
		||||
  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');
 | 
			
		||||
    tcFind.mockImplementation((tool: string, version: string) => {
 | 
			
		||||
      const semverRange = new semver.Range(version);
 | 
			
		||||
      let graalpyPath = '';
 | 
			
		||||
      if (semver.satisfies('23.0.0', semverRange)) {
 | 
			
		||||
        graalpyPath = path.join(toolDir, 'GraalPy', '23.0.0', architecture);
 | 
			
		||||
      }
 | 
			
		||||
      return graalpyPath;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    spyDownloadTool = jest.spyOn(tc, 'downloadTool');
 | 
			
		||||
    spyDownloadTool.mockImplementation(() => path.join(tempDir, 'GraalPy'));
 | 
			
		||||
 | 
			
		||||
    spyExtractZip = jest.spyOn(tc, 'extractZip');
 | 
			
		||||
    spyExtractZip.mockImplementation(() => tempDir);
 | 
			
		||||
 | 
			
		||||
    spyExtractTar = jest.spyOn(tc, 'extractTar');
 | 
			
		||||
    spyExtractTar.mockImplementation(() => tempDir);
 | 
			
		||||
 | 
			
		||||
    spyFsReadDir = jest.spyOn(fs, 'readdirSync');
 | 
			
		||||
    spyFsReadDir.mockImplementation((directory: string) => ['GraalPyTest']);
 | 
			
		||||
 | 
			
		||||
    spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
 | 
			
		||||
    spyHttpClient.mockImplementation(
 | 
			
		||||
      async (): Promise<ifm.ITypedResponse<IGraalPyManifestRelease[]>> => {
 | 
			
		||||
        const result = JSON.stringify(manifestData);
 | 
			
		||||
        return {
 | 
			
		||||
          statusCode: 200,
 | 
			
		||||
          headers: {},
 | 
			
		||||
          result: JSON.parse(result) as IGraalPyManifestRelease[]
 | 
			
		||||
        };
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    spyExec = jest.spyOn(exec, 'exec');
 | 
			
		||||
    spyExec.mockImplementation(() => undefined);
 | 
			
		||||
 | 
			
		||||
    spySymlinkSync = jest.spyOn(fs, 'symlinkSync');
 | 
			
		||||
    spySymlinkSync.mockImplementation(() => undefined);
 | 
			
		||||
 | 
			
		||||
    spyExistsSync = jest.spyOn(fs, 'existsSync');
 | 
			
		||||
    spyExistsSync.mockReturnValue(true);
 | 
			
		||||
 | 
			
		||||
    spyCoreAddPath = jest.spyOn(core, 'addPath');
 | 
			
		||||
 | 
			
		||||
    spyCoreExportVariable = jest.spyOn(core, 'exportVariable');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  afterEach(() => {
 | 
			
		||||
    jest.resetAllMocks();
 | 
			
		||||
    jest.clearAllMocks();
 | 
			
		||||
    jest.restoreAllMocks();
 | 
			
		||||
    process.env = env;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('found GraalPy in toolcache', async () => {
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findGraalPyVersion(
 | 
			
		||||
        'graalpy-23.0',
 | 
			
		||||
        architecture,
 | 
			
		||||
        true,
 | 
			
		||||
        false,
 | 
			
		||||
        false
 | 
			
		||||
      )
 | 
			
		||||
    ).resolves.toEqual('23.0.0');
 | 
			
		||||
    expect(spyCoreAddPath).toHaveBeenCalled();
 | 
			
		||||
    expect(spyCoreExportVariable).toHaveBeenCalledWith(
 | 
			
		||||
      'pythonLocation',
 | 
			
		||||
      expect.anything()
 | 
			
		||||
    );
 | 
			
		||||
    expect(spyCoreExportVariable).toHaveBeenCalledWith(
 | 
			
		||||
      'PKG_CONFIG_PATH',
 | 
			
		||||
      expect.anything()
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('throw on invalid input format', async () => {
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findGraalPyVersion('graalpy-x23', architecture, true, false, false)
 | 
			
		||||
    ).rejects.toThrow();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('found and install successfully', async () => {
 | 
			
		||||
    spyCacheDir = jest.spyOn(tc, 'cacheDir');
 | 
			
		||||
    spyCacheDir.mockImplementation(() =>
 | 
			
		||||
      path.join(toolDir, 'GraalPy', '23.0.0', architecture)
 | 
			
		||||
    );
 | 
			
		||||
    spyChmodSync = jest.spyOn(fs, 'chmodSync');
 | 
			
		||||
    spyChmodSync.mockImplementation(() => undefined);
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findGraalPyVersion(
 | 
			
		||||
        'graalpy-23.0.0',
 | 
			
		||||
        architecture,
 | 
			
		||||
        true,
 | 
			
		||||
        false,
 | 
			
		||||
        false
 | 
			
		||||
      )
 | 
			
		||||
    ).resolves.toEqual('23.0.0');
 | 
			
		||||
    expect(spyCoreAddPath).toHaveBeenCalled();
 | 
			
		||||
    expect(spyCoreExportVariable).toHaveBeenCalledWith(
 | 
			
		||||
      'pythonLocation',
 | 
			
		||||
      expect.anything()
 | 
			
		||||
    );
 | 
			
		||||
    expect(spyCoreExportVariable).toHaveBeenCalledWith(
 | 
			
		||||
      'PKG_CONFIG_PATH',
 | 
			
		||||
      expect.anything()
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('found and install successfully without environment update', async () => {
 | 
			
		||||
    spyCacheDir = jest.spyOn(tc, 'cacheDir');
 | 
			
		||||
    spyCacheDir.mockImplementation(() =>
 | 
			
		||||
      path.join(toolDir, 'GraalPy', '23.0.0', architecture)
 | 
			
		||||
    );
 | 
			
		||||
    spyChmodSync = jest.spyOn(fs, 'chmodSync');
 | 
			
		||||
    spyChmodSync.mockImplementation(() => undefined);
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findGraalPyVersion(
 | 
			
		||||
        'graalpy-23.0.0',
 | 
			
		||||
        architecture,
 | 
			
		||||
        false,
 | 
			
		||||
        false,
 | 
			
		||||
        false
 | 
			
		||||
      )
 | 
			
		||||
    ).resolves.toEqual('23.0.0');
 | 
			
		||||
    expect(spyCoreAddPath).not.toHaveBeenCalled();
 | 
			
		||||
    expect(spyCoreExportVariable).not.toHaveBeenCalled();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('throw if release is not found', async () => {
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findGraalPyVersion(
 | 
			
		||||
        'graalpy-19.0.0',
 | 
			
		||||
        architecture,
 | 
			
		||||
        true,
 | 
			
		||||
        false,
 | 
			
		||||
        false
 | 
			
		||||
      )
 | 
			
		||||
    ).rejects.toThrow(
 | 
			
		||||
      `GraalPy version 19.0.0 with arch ${architecture} not found`
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('check-latest enabled version found and used from toolcache', async () => {
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findGraalPyVersion(
 | 
			
		||||
        'graalpy-23.0.0',
 | 
			
		||||
        architecture,
 | 
			
		||||
        false,
 | 
			
		||||
        true,
 | 
			
		||||
        false
 | 
			
		||||
      )
 | 
			
		||||
    ).resolves.toEqual('23.0.0');
 | 
			
		||||
 | 
			
		||||
    expect(infoSpy).toHaveBeenCalledWith('Resolved as GraalPy 23.0.0');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('check-latest enabled version found and install successfully', async () => {
 | 
			
		||||
    spyCacheDir = jest.spyOn(tc, 'cacheDir');
 | 
			
		||||
    spyCacheDir.mockImplementation(() =>
 | 
			
		||||
      path.join(toolDir, 'GraalPy', '23.0.0', architecture)
 | 
			
		||||
    );
 | 
			
		||||
    spyChmodSync = jest.spyOn(fs, 'chmodSync');
 | 
			
		||||
    spyChmodSync.mockImplementation(() => undefined);
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findGraalPyVersion(
 | 
			
		||||
        'graalpy-23.0.0',
 | 
			
		||||
        architecture,
 | 
			
		||||
        false,
 | 
			
		||||
        true,
 | 
			
		||||
        false
 | 
			
		||||
      )
 | 
			
		||||
    ).resolves.toEqual('23.0.0');
 | 
			
		||||
    expect(infoSpy).toHaveBeenCalledWith('Resolved as GraalPy 23.0.0');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  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 graalpyPath = '';
 | 
			
		||||
      if (semver.satisfies('22.3.4', semverRange)) {
 | 
			
		||||
        graalpyPath = path.join(toolDir, 'GraalPy', '22.3.4', architecture);
 | 
			
		||||
      }
 | 
			
		||||
      return graalpyPath;
 | 
			
		||||
    });
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findGraalPyVersion(
 | 
			
		||||
        'graalpy-22.3.4',
 | 
			
		||||
        architecture,
 | 
			
		||||
        false,
 | 
			
		||||
        true,
 | 
			
		||||
        false
 | 
			
		||||
      )
 | 
			
		||||
    ).resolves.toEqual('22.3.4');
 | 
			
		||||
 | 
			
		||||
    expect(infoSpy).toHaveBeenCalledWith(
 | 
			
		||||
      'Failed to resolve GraalPy 22.3.4 from manifest'
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('found and install successfully, pre-release fallback', async () => {
 | 
			
		||||
    spyCacheDir = jest.spyOn(tc, 'cacheDir');
 | 
			
		||||
    spyCacheDir.mockImplementation(() =>
 | 
			
		||||
      path.join(toolDir, 'GraalPy', '23.1', architecture)
 | 
			
		||||
    );
 | 
			
		||||
    spyChmodSync = jest.spyOn(fs, 'chmodSync');
 | 
			
		||||
    spyChmodSync.mockImplementation(() => undefined);
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findGraalPyVersion(
 | 
			
		||||
        'graalpy23.1',
 | 
			
		||||
        architecture,
 | 
			
		||||
        false,
 | 
			
		||||
        false,
 | 
			
		||||
        false
 | 
			
		||||
      )
 | 
			
		||||
    ).rejects.toThrow();
 | 
			
		||||
    await expect(
 | 
			
		||||
      finder.findGraalPyVersion('graalpy23.1', architecture, false, false, true)
 | 
			
		||||
    ).resolves.toEqual('23.1.0-a.1');
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
		Reference in New Issue
	
	Block a user