Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Api rate limit error fix #950

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion __tests__/install-python.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,25 @@ import * as tc from '@actions/tool-cache';
jest.mock('@actions/http-client');
jest.mock('@actions/tool-cache');

const mockManifest = [{version: '1.0.0'}];
const mockManifest = [
{
version: '3.9.0',
stable: true,
release_url: 'https://example.com/release-url',
files: [
{
filename: 'python-3.9.0-macosx10.9.pkg',
arch: 'x64',
platform: 'darwin',
download_url: 'https://example.com/download-url'
}
]
}
];

beforeEach(() => {
jest.resetAllMocks();
});

describe('getManifest', () => {
it('should return manifest from repo', async () => {
Expand Down
75 changes: 52 additions & 23 deletions dist/setup/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -91646,20 +91646,49 @@ exports.findReleaseFromManifest = findReleaseFromManifest;
function getManifest() {
return __awaiter(this, void 0, void 0, function* () {
try {
return yield getManifestFromRepo();
const manifestFromRepo = yield getManifestFromRepo();
core.info('Successfully fetched the manifest from the repo.');
validateManifest(manifestFromRepo);
return manifestFromRepo;
}
catch (err) {
core.debug('Fetching the manifest via the API failed.');
if (err instanceof Error) {
core.debug(err.message);
}
logError('Fetching the manifest via the API failed.', err);
}
try {
const manifestFromURL = yield getManifestFromURL();
core.info('Successfully fetched the manifest from the URL.');
return manifestFromURL;
}
catch (err) {
logError('Fetching the manifest via the URL failed.', err);
// Rethrow the error or return a default value
throw new Error('Failed to fetch the manifest from both the repo and the URL.');
}
return yield getManifestFromURL();
});
}
exports.getManifest = getManifest;
function validateManifest(manifest) {
if (!Array.isArray(manifest) || !manifest.every(isValidManifestEntry)) {
throw new Error('Invalid manifest response');
}
}
function isValidManifestEntry(entry) {
return (typeof entry.version === 'string' &&
typeof entry.stable === 'boolean' &&
typeof entry.release_url === 'string' &&
Array.isArray(entry.files) &&
entry.files.every(isValidFileEntry));
}
function isValidFileEntry(file) {
return (typeof file.filename === 'string' &&
typeof file.arch === 'string' &&
typeof file.platform === 'string' &&
(typeof file.platform_version === 'string' ||
file.platform_version === undefined) &&
typeof file.download_url === 'string');
}
function getManifestFromRepo() {
core.debug(`Getting manifest from ${MANIFEST_REPO_OWNER}/${MANIFEST_REPO_NAME}@${MANIFEST_REPO_BRANCH}`);
core.info(`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.getManifestFromRepo = getManifestFromRepo;
Expand Down Expand Up @@ -91690,34 +91719,29 @@ function installPython(workingDirectory) {
}
}
};
if (utils_1.IS_WINDOWS) {
yield exec.exec('powershell', ['./setup.ps1'], options);
}
else {
yield exec.exec('bash', ['./setup.sh'], options);
}
const script = utils_1.IS_WINDOWS ? 'powershell ./setup.ps1' : 'bash ./setup.sh';
yield exec.exec(script, [], options);
});
}
function installCpythonFromRelease(release) {
return __awaiter(this, void 0, void 0, function* () {
const downloadUrl = release.files[0].download_url;
core.info(`Download from "${downloadUrl}"`);
let pythonPath = '';
try {
const fileName = (0, utils_1.getDownloadFileName)(downloadUrl);
pythonPath = yield tc.downloadTool(downloadUrl, fileName, AUTH);
const pythonPath = yield tc.downloadTool(downloadUrl, fileName, AUTH);
core.info('Extract downloaded archive');
let pythonExtractedFolder;
if (utils_1.IS_WINDOWS) {
pythonExtractedFolder = yield tc.extractZip(pythonPath);
}
else {
pythonExtractedFolder = yield tc.extractTar(pythonPath);
}
const pythonExtractedFolder = utils_1.IS_WINDOWS
? yield tc.extractZip(pythonPath)
: yield tc.extractTar(pythonPath);
core.info('Execute installation script');
yield installPython(pythonExtractedFolder);
}
catch (err) {
handleDownloadError(err);
throw err;
}
function handleDownloadError(err) {
if (err instanceof tc.HTTPError) {
// Rate limit?
if (err.httpStatusCode === 403 || err.httpStatusCode === 429) {
Expand All @@ -91730,11 +91754,16 @@ function installCpythonFromRelease(release) {
core.debug(err.stack);
}
}
throw err;
}
});
}
exports.installCpythonFromRelease = installCpythonFromRelease;
function logError(message, err) {
core.info(message);
if (err instanceof Error) {
core.info(err.message);
}
}


/***/ }),
Expand Down
84 changes: 62 additions & 22 deletions src/install-python.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,60 @@ export async function findReleaseFromManifest(
manifest,
architecture
);

return foundRelease;
}

export async function getManifest(): Promise<tc.IToolRelease[]> {
try {
return await getManifestFromRepo();
const manifestFromRepo = await getManifestFromRepo();
core.info('Successfully fetched the manifest from the repo.');
validateManifest(manifestFromRepo);
return manifestFromRepo;
} catch (err) {
core.debug('Fetching the manifest via the API failed.');
if (err instanceof Error) {
core.debug(err.message);
}
logError('Fetching the manifest via the API failed.', err);
}
try {
const manifestFromURL = await getManifestFromURL();
core.info('Successfully fetched the manifest from the URL.');
return manifestFromURL;
} catch (err) {
logError('Fetching the manifest via the URL failed.', err);
// Rethrow the error or return a default value
throw new Error(
'Failed to fetch the manifest from both the repo and the URL.'
);
}
}

function validateManifest(manifest: any): void {
if (!Array.isArray(manifest) || !manifest.every(isValidManifestEntry)) {
throw new Error('Invalid manifest response');
}
return await getManifestFromURL();
}

function isValidManifestEntry(entry: any): boolean {
return (
typeof entry.version === 'string' &&
typeof entry.stable === 'boolean' &&
typeof entry.release_url === 'string' &&
Array.isArray(entry.files) &&
entry.files.every(isValidFileEntry)
);
}

function isValidFileEntry(file: any): boolean {
return (
typeof file.filename === 'string' &&
typeof file.arch === 'string' &&
typeof file.platform === 'string' &&
(typeof file.platform_version === 'string' ||
file.platform_version === undefined) &&
typeof file.download_url === 'string'
);
}

export function getManifestFromRepo(): Promise<tc.IToolRelease[]> {
core.debug(
core.info(
`Getting manifest from ${MANIFEST_REPO_OWNER}/${MANIFEST_REPO_NAME}@${MANIFEST_REPO_BRANCH}`
);
return tc.getManifestFromRepo(
Expand Down Expand Up @@ -85,32 +121,30 @@ async function installPython(workingDirectory: string) {
}
};

if (IS_WINDOWS) {
await exec.exec('powershell', ['./setup.ps1'], options);
} else {
await exec.exec('bash', ['./setup.sh'], options);
}
const script = IS_WINDOWS ? 'powershell ./setup.ps1' : 'bash ./setup.sh';
await exec.exec(script, [], options);
}

export async function installCpythonFromRelease(release: tc.IToolRelease) {
const downloadUrl = release.files[0].download_url;

core.info(`Download from "${downloadUrl}"`);
let pythonPath = '';
try {
const fileName = getDownloadFileName(downloadUrl);
pythonPath = await tc.downloadTool(downloadUrl, fileName, AUTH);
const pythonPath = await tc.downloadTool(downloadUrl, fileName, AUTH);
core.info('Extract downloaded archive');
let pythonExtractedFolder;
if (IS_WINDOWS) {
pythonExtractedFolder = await tc.extractZip(pythonPath);
} else {
pythonExtractedFolder = await tc.extractTar(pythonPath);
}
const pythonExtractedFolder = IS_WINDOWS
? await tc.extractZip(pythonPath)
: await tc.extractTar(pythonPath);

core.info('Execute installation script');
await installPython(pythonExtractedFolder);
} catch (err) {
handleDownloadError(err);
throw err;
}

function handleDownloadError(err: any): void {
if (err instanceof tc.HTTPError) {
// Rate limit?
if (err.httpStatusCode === 403 || err.httpStatusCode === 429) {
Expand All @@ -124,6 +158,12 @@ export async function installCpythonFromRelease(release: tc.IToolRelease) {
core.debug(err.stack);
}
}
throw err;
}
}

function logError(message: string, err: any): void {
core.info(message);
if (err instanceof Error) {
core.info(err.message);
}
}
Loading