From 01408cef88a00c4c39b02491725a369336e9d7a4 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Tue, 28 Jun 2022 15:17:50 +0200
Subject: [PATCH 01/77] Update cache-save.ts to support @actions/cache v3.0.0
lib
Made package.json and package-lock.json to use @actions/cache v3.0.0,
updated logic of the cache-save operation and added unit-tests
---
__tests__/cache-save.test.ts | 53 +++
dist/cache-save/index.js | 673 ++++++++++++++++++++---------------
dist/setup/index.js | 657 ++++++++++++++++++++--------------
package-lock.json | 34 +-
package.json | 4 +-
src/cache-save.ts | 14 +-
6 files changed, 858 insertions(+), 577 deletions(-)
diff --git a/__tests__/cache-save.test.ts b/__tests__/cache-save.test.ts
index 3fad9a2d..f90ca7f6 100644
--- a/__tests__/cache-save.test.ts
+++ b/__tests__/cache-save.test.ts
@@ -212,6 +212,59 @@ describe('run', () => {
);
expect(setFailedSpy).not.toHaveBeenCalled();
});
+
+ it('saves with -1 cacheId , should not fail workflow', async () => {
+ inputs['cache'] = 'poetry';
+ getStateSpy.mockImplementation((name: string) => {
+ if (name === State.STATE_CACHE_PRIMARY_KEY) {
+ return poetryLockHash;
+ } else if (name === State.CACHE_PATHS) {
+ return JSON.stringify([__dirname]);
+ } else {
+ return requirementsHash;
+ }
+ });
+
+ saveCacheSpy.mockImplementation(() => {
+ return -1;
+ });
+
+ await run();
+
+ expect(getInputSpy).toHaveBeenCalled();
+ expect(getStateSpy).toHaveBeenCalledTimes(3);
+ expect(infoSpy).not.toHaveBeenCalled();
+ expect(saveCacheSpy).toHaveBeenCalled();
+ expect(infoSpy).not.toHaveBeenLastCalledWith(
+ `Cache saved with the key: ${poetryLockHash}`
+ );
+ expect(setFailedSpy).not.toHaveBeenCalled();
+ });
+
+ it('saves with error from toolkit, should fail workflow', async () => {
+ inputs['cache'] = 'npm';
+ getStateSpy.mockImplementation((name: string) => {
+ if (name === State.STATE_CACHE_PRIMARY_KEY) {
+ return poetryLockHash;
+ } else if (name === State.CACHE_PATHS) {
+ return JSON.stringify([__dirname]);
+ } else {
+ return requirementsHash;
+ }
+ });
+
+ saveCacheSpy.mockImplementation(() => {
+ throw new cache.ValidationError('Validation failed');
+ });
+
+ await run();
+
+ expect(getInputSpy).toHaveBeenCalled();
+ expect(getStateSpy).toHaveBeenCalledTimes(3);
+ expect(infoSpy).not.toHaveBeenCalledWith();
+ expect(saveCacheSpy).toHaveBeenCalled();
+ expect(setFailedSpy).toHaveBeenCalled();
+ });
});
afterEach(() => {
diff --git a/dist/cache-save/index.js b/dist/cache-save/index.js
index 35cedd90..700437b7 100644
--- a/dist/cache-save/index.js
+++ b/dist/cache-save/index.js
@@ -90,17 +90,18 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
checkKey(key);
}
const compressionMethod = yield utils.getCompressionMethod();
- // path are needed to compute version
- const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
- compressionMethod
- });
- if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
- // Cache not found
- return undefined;
- }
- const archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
- core.debug(`Archive Path: ${archivePath}`);
+ let archivePath = '';
try {
+ // path are needed to compute version
+ const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
+ compressionMethod
+ });
+ if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
+ // Cache not found
+ return undefined;
+ }
+ archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
+ core.debug(`Archive Path: ${archivePath}`);
// Download the cache from the cache entry
yield cacheHttpClient.downloadCache(cacheEntry.archiveLocation, archivePath, options);
if (core.isDebug()) {
@@ -110,6 +111,17 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
core.info(`Cache Size: ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B)`);
yield tar_1.extractTar(archivePath, compressionMethod);
core.info('Cache restored successfully');
+ return cacheEntry.cacheKey;
+ }
+ catch (error) {
+ const typedError = error;
+ if (typedError.name === ValidationError.name) {
+ throw error;
+ }
+ else {
+ // Supress all non-validation cache related errors because caching should be optional
+ core.warning(`Failed to restore: ${error.message}`);
+ }
}
finally {
// Try to delete the archive to save space
@@ -120,7 +132,7 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
core.debug(`Failed to delete archive: ${error}`);
}
}
- return cacheEntry.cacheKey;
+ return undefined;
});
}
exports.restoreCache = restoreCache;
@@ -138,10 +150,13 @@ function saveCache(paths, key, options) {
checkPaths(paths);
checkKey(key);
const compressionMethod = yield utils.getCompressionMethod();
- let cacheId = null;
+ let cacheId = -1;
const cachePaths = yield utils.resolvePaths(paths);
core.debug('Cache Paths:');
core.debug(`${JSON.stringify(cachePaths)}`);
+ if (cachePaths.length === 0) {
+ throw new Error(`Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.`);
+ }
const archiveFolder = yield utils.createTempDirectory();
const archivePath = path.join(archiveFolder, utils.getCacheFileName(compressionMethod));
core.debug(`Archive Path: ${archivePath}`);
@@ -174,6 +189,18 @@ function saveCache(paths, key, options) {
core.debug(`Saving Cache (ID: ${cacheId})`);
yield cacheHttpClient.saveCache(cacheId, archivePath, options);
}
+ catch (error) {
+ const typedError = error;
+ if (typedError.name === ValidationError.name) {
+ throw error;
+ }
+ else if (typedError.name === ReserveCacheError.name) {
+ core.info(`Failed to save: ${typedError.message}`);
+ }
+ else {
+ core.warning(`Failed to save: ${typedError.message}`);
+ }
+ }
finally {
// Try to delete the archive to save space
try {
@@ -214,8 +241,8 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(7320);
-const auth_1 = __nccwpck_require__(7093);
+const http_client_1 = __nccwpck_require__(1825);
+const auth_1 = __nccwpck_require__(2001);
const crypto = __importStar(__nccwpck_require__(6113));
const fs = __importStar(__nccwpck_require__(7147));
const url_1 = __nccwpck_require__(7310);
@@ -647,7 +674,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(7320);
+const http_client_1 = __nccwpck_require__(1825);
const storage_blob_1 = __nccwpck_require__(4100);
const buffer = __importStar(__nccwpck_require__(4300));
const fs = __importStar(__nccwpck_require__(7147));
@@ -885,7 +912,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(7320);
+const http_client_1 = __nccwpck_require__(1825);
const constants_1 = __nccwpck_require__(8840);
function isSuccessStatusCode(statusCode) {
if (!statusCode) {
@@ -962,7 +989,7 @@ function retryTypedResponse(name, method, maxAttempts = constants_1.DefaultRetry
return __awaiter(this, void 0, void 0, function* () {
return yield retry(name, method, (response) => response.statusCode, maxAttempts, delay,
// If the error object contains the statusCode property, extract it and return
- // an ITypedResponse so it can be processed by the retry logic.
+ // an TypedResponse so it can be processed by the retry logic.
(error) => {
if (error instanceof http_client_1.HttpClientError) {
return {
@@ -1120,6 +1147,8 @@ function createTar(archiveFolder, sourceDirectories, compressionMethod) {
...getCompressionProgram(),
'-cf',
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
+ '--exclude',
+ cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'-P',
'-C',
workingDirectory.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
@@ -2292,28 +2321,41 @@ exports.SearchState = SearchState;
/***/ }),
-/***/ 7093:
-/***/ ((__unused_webpack_module, exports) => {
+/***/ 2001:
+/***/ (function(__unused_webpack_module, exports) {
"use strict";
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.PersonalAccessTokenCredentialHandler = exports.BearerCredentialHandler = exports.BasicCredentialHandler = void 0;
class BasicCredentialHandler {
constructor(username, password) {
this.username = username;
this.password = password;
}
prepareRequest(options) {
- options.headers['Authorization'] =
- 'Basic ' +
- Buffer.from(this.username + ':' + this.password).toString('base64');
+ if (!options.headers) {
+ throw Error('The request has no headers');
+ }
+ options.headers['Authorization'] = `Basic ${Buffer.from(`${this.username}:${this.password}`).toString('base64')}`;
}
// This handler cannot handle 401
- canHandleAuthentication(response) {
+ canHandleAuthentication() {
return false;
}
- handleAuthentication(httpClient, requestInfo, objs) {
- return null;
+ handleAuthentication() {
+ return __awaiter(this, void 0, void 0, function* () {
+ throw new Error('not implemented');
+ });
}
}
exports.BasicCredentialHandler = BasicCredentialHandler;
@@ -2324,14 +2366,19 @@ class BearerCredentialHandler {
// currently implements pre-authorization
// TODO: support preAuth = false where it hooks on 401
prepareRequest(options) {
- options.headers['Authorization'] = 'Bearer ' + this.token;
+ if (!options.headers) {
+ throw Error('The request has no headers');
+ }
+ options.headers['Authorization'] = `Bearer ${this.token}`;
}
// This handler cannot handle 401
- canHandleAuthentication(response) {
+ canHandleAuthentication() {
return false;
}
- handleAuthentication(httpClient, requestInfo, objs) {
- return null;
+ handleAuthentication() {
+ return __awaiter(this, void 0, void 0, function* () {
+ throw new Error('not implemented');
+ });
}
}
exports.BearerCredentialHandler = BearerCredentialHandler;
@@ -2342,32 +2389,66 @@ class PersonalAccessTokenCredentialHandler {
// currently implements pre-authorization
// TODO: support preAuth = false where it hooks on 401
prepareRequest(options) {
- options.headers['Authorization'] =
- 'Basic ' + Buffer.from('PAT:' + this.token).toString('base64');
+ if (!options.headers) {
+ throw Error('The request has no headers');
+ }
+ options.headers['Authorization'] = `Basic ${Buffer.from(`PAT:${this.token}`).toString('base64')}`;
}
// This handler cannot handle 401
- canHandleAuthentication(response) {
+ canHandleAuthentication() {
return false;
}
- handleAuthentication(httpClient, requestInfo, objs) {
- return null;
+ handleAuthentication() {
+ return __awaiter(this, void 0, void 0, function* () {
+ throw new Error('not implemented');
+ });
}
}
exports.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHandler;
-
+//# sourceMappingURL=auth.js.map
/***/ }),
-/***/ 7320:
-/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
+/***/ 1825:
+/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
"use strict";
+/* eslint-disable @typescript-eslint/no-explicit-any */
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
Object.defineProperty(exports, "__esModule", ({ value: true }));
-const http = __nccwpck_require__(3685);
-const https = __nccwpck_require__(5687);
-const pm = __nccwpck_require__(7326);
-let tunnel;
+exports.HttpClient = exports.isHttps = exports.HttpClientResponse = exports.HttpClientError = exports.getProxyUrl = exports.MediaTypes = exports.Headers = exports.HttpCodes = void 0;
+const http = __importStar(__nccwpck_require__(3685));
+const https = __importStar(__nccwpck_require__(5687));
+const pm = __importStar(__nccwpck_require__(4977));
+const tunnel = __importStar(__nccwpck_require__(4294));
var HttpCodes;
(function (HttpCodes) {
HttpCodes[HttpCodes["OK"] = 200] = "OK";
@@ -2412,7 +2493,7 @@ var MediaTypes;
* @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
*/
function getProxyUrl(serverUrl) {
- let proxyUrl = pm.getProxyUrl(new URL(serverUrl));
+ const proxyUrl = pm.getProxyUrl(new URL(serverUrl));
return proxyUrl ? proxyUrl.href : '';
}
exports.getProxyUrl = getProxyUrl;
@@ -2445,20 +2526,22 @@ class HttpClientResponse {
this.message = message;
}
readBody() {
- return new Promise(async (resolve, reject) => {
- let output = Buffer.alloc(0);
- this.message.on('data', (chunk) => {
- output = Buffer.concat([output, chunk]);
- });
- this.message.on('end', () => {
- resolve(output.toString());
- });
+ return __awaiter(this, void 0, void 0, function* () {
+ return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
+ let output = Buffer.alloc(0);
+ this.message.on('data', (chunk) => {
+ output = Buffer.concat([output, chunk]);
+ });
+ this.message.on('end', () => {
+ resolve(output.toString());
+ });
+ }));
});
}
}
exports.HttpClientResponse = HttpClientResponse;
function isHttps(requestUrl) {
- let parsedUrl = new URL(requestUrl);
+ const parsedUrl = new URL(requestUrl);
return parsedUrl.protocol === 'https:';
}
exports.isHttps = isHttps;
@@ -2501,141 +2584,169 @@ class HttpClient {
}
}
options(requestUrl, additionalHeaders) {
- return this.request('OPTIONS', requestUrl, null, additionalHeaders || {});
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('OPTIONS', requestUrl, null, additionalHeaders || {});
+ });
}
get(requestUrl, additionalHeaders) {
- return this.request('GET', requestUrl, null, additionalHeaders || {});
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('GET', requestUrl, null, additionalHeaders || {});
+ });
}
del(requestUrl, additionalHeaders) {
- return this.request('DELETE', requestUrl, null, additionalHeaders || {});
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('DELETE', requestUrl, null, additionalHeaders || {});
+ });
}
post(requestUrl, data, additionalHeaders) {
- return this.request('POST', requestUrl, data, additionalHeaders || {});
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('POST', requestUrl, data, additionalHeaders || {});
+ });
}
patch(requestUrl, data, additionalHeaders) {
- return this.request('PATCH', requestUrl, data, additionalHeaders || {});
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('PATCH', requestUrl, data, additionalHeaders || {});
+ });
}
put(requestUrl, data, additionalHeaders) {
- return this.request('PUT', requestUrl, data, additionalHeaders || {});
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('PUT', requestUrl, data, additionalHeaders || {});
+ });
}
head(requestUrl, additionalHeaders) {
- return this.request('HEAD', requestUrl, null, additionalHeaders || {});
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('HEAD', requestUrl, null, additionalHeaders || {});
+ });
}
sendStream(verb, requestUrl, stream, additionalHeaders) {
- return this.request(verb, requestUrl, stream, additionalHeaders);
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request(verb, requestUrl, stream, additionalHeaders);
+ });
}
/**
* Gets a typed object from an endpoint
* Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise
*/
- async getJson(requestUrl, additionalHeaders = {}) {
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- let res = await this.get(requestUrl, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
+ getJson(requestUrl, additionalHeaders = {}) {
+ return __awaiter(this, void 0, void 0, function* () {
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ const res = yield this.get(requestUrl, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ });
}
- async postJson(requestUrl, obj, additionalHeaders = {}) {
- let data = JSON.stringify(obj, null, 2);
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
- let res = await this.post(requestUrl, data, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
+ postJson(requestUrl, obj, additionalHeaders = {}) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const data = JSON.stringify(obj, null, 2);
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
+ const res = yield this.post(requestUrl, data, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ });
}
- async putJson(requestUrl, obj, additionalHeaders = {}) {
- let data = JSON.stringify(obj, null, 2);
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
- let res = await this.put(requestUrl, data, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
+ putJson(requestUrl, obj, additionalHeaders = {}) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const data = JSON.stringify(obj, null, 2);
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
+ const res = yield this.put(requestUrl, data, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ });
}
- async patchJson(requestUrl, obj, additionalHeaders = {}) {
- let data = JSON.stringify(obj, null, 2);
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
- let res = await this.patch(requestUrl, data, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
+ patchJson(requestUrl, obj, additionalHeaders = {}) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const data = JSON.stringify(obj, null, 2);
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
+ const res = yield this.patch(requestUrl, data, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ });
}
/**
* Makes a raw http request.
* All other methods such as get, post, patch, and request ultimately call this.
* Prefer get, del, post and patch
*/
- async request(verb, requestUrl, data, headers) {
- if (this._disposed) {
- throw new Error('Client has already been disposed.');
- }
- let parsedUrl = new URL(requestUrl);
- let info = this._prepareRequest(verb, parsedUrl, headers);
- // Only perform retries on reads since writes may not be idempotent.
- let maxTries = this._allowRetries && RetryableHttpVerbs.indexOf(verb) != -1
- ? this._maxRetries + 1
- : 1;
- let numTries = 0;
- let response;
- while (numTries < maxTries) {
- response = await this.requestRaw(info, data);
- // Check if it's an authentication challenge
- if (response &&
- response.message &&
- response.message.statusCode === HttpCodes.Unauthorized) {
- let authenticationHandler;
- for (let i = 0; i < this.handlers.length; i++) {
- if (this.handlers[i].canHandleAuthentication(response)) {
- authenticationHandler = this.handlers[i];
- break;
- }
- }
- if (authenticationHandler) {
- return authenticationHandler.handleAuthentication(this, info, data);
- }
- else {
- // We have received an unauthorized response but have no handlers to handle it.
- // Let the response return to the caller.
- return response;
- }
+ request(verb, requestUrl, data, headers) {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (this._disposed) {
+ throw new Error('Client has already been disposed.');
}
- let redirectsRemaining = this._maxRedirects;
- while (HttpRedirectCodes.indexOf(response.message.statusCode) != -1 &&
- this._allowRedirects &&
- redirectsRemaining > 0) {
- const redirectUrl = response.message.headers['location'];
- if (!redirectUrl) {
- // if there's no location to redirect to, we won't
- break;
- }
- let parsedRedirectUrl = new URL(redirectUrl);
- if (parsedUrl.protocol == 'https:' &&
- parsedUrl.protocol != parsedRedirectUrl.protocol &&
- !this._allowRedirectDowngrade) {
- throw new Error('Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.');
- }
- // we need to finish reading the response before reassigning response
- // which will leak the open socket.
- await response.readBody();
- // strip authorization header if redirected to a different hostname
- if (parsedRedirectUrl.hostname !== parsedUrl.hostname) {
- for (let header in headers) {
- // header names are case insensitive
- if (header.toLowerCase() === 'authorization') {
- delete headers[header];
+ const parsedUrl = new URL(requestUrl);
+ let info = this._prepareRequest(verb, parsedUrl, headers);
+ // Only perform retries on reads since writes may not be idempotent.
+ const maxTries = this._allowRetries && RetryableHttpVerbs.includes(verb)
+ ? this._maxRetries + 1
+ : 1;
+ let numTries = 0;
+ let response;
+ do {
+ response = yield this.requestRaw(info, data);
+ // Check if it's an authentication challenge
+ if (response &&
+ response.message &&
+ response.message.statusCode === HttpCodes.Unauthorized) {
+ let authenticationHandler;
+ for (const handler of this.handlers) {
+ if (handler.canHandleAuthentication(response)) {
+ authenticationHandler = handler;
+ break;
}
}
+ if (authenticationHandler) {
+ return authenticationHandler.handleAuthentication(this, info, data);
+ }
+ else {
+ // We have received an unauthorized response but have no handlers to handle it.
+ // Let the response return to the caller.
+ return response;
+ }
}
- // let's make the request with the new redirectUrl
- info = this._prepareRequest(verb, parsedRedirectUrl, headers);
- response = await this.requestRaw(info, data);
- redirectsRemaining--;
- }
- if (HttpResponseRetryCodes.indexOf(response.message.statusCode) == -1) {
- // If not a retry code, return immediately instead of retrying
- return response;
- }
- numTries += 1;
- if (numTries < maxTries) {
- await response.readBody();
- await this._performExponentialBackoff(numTries);
- }
- }
- return response;
+ let redirectsRemaining = this._maxRedirects;
+ while (response.message.statusCode &&
+ HttpRedirectCodes.includes(response.message.statusCode) &&
+ this._allowRedirects &&
+ redirectsRemaining > 0) {
+ const redirectUrl = response.message.headers['location'];
+ if (!redirectUrl) {
+ // if there's no location to redirect to, we won't
+ break;
+ }
+ const parsedRedirectUrl = new URL(redirectUrl);
+ if (parsedUrl.protocol === 'https:' &&
+ parsedUrl.protocol !== parsedRedirectUrl.protocol &&
+ !this._allowRedirectDowngrade) {
+ throw new Error('Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.');
+ }
+ // we need to finish reading the response before reassigning response
+ // which will leak the open socket.
+ yield response.readBody();
+ // strip authorization header if redirected to a different hostname
+ if (parsedRedirectUrl.hostname !== parsedUrl.hostname) {
+ for (const header in headers) {
+ // header names are case insensitive
+ if (header.toLowerCase() === 'authorization') {
+ delete headers[header];
+ }
+ }
+ }
+ // let's make the request with the new redirectUrl
+ info = this._prepareRequest(verb, parsedRedirectUrl, headers);
+ response = yield this.requestRaw(info, data);
+ redirectsRemaining--;
+ }
+ if (!response.message.statusCode ||
+ !HttpResponseRetryCodes.includes(response.message.statusCode)) {
+ // If not a retry code, return immediately instead of retrying
+ return response;
+ }
+ numTries += 1;
+ if (numTries < maxTries) {
+ yield response.readBody();
+ yield this._performExponentialBackoff(numTries);
+ }
+ } while (numTries < maxTries);
+ return response;
+ });
}
/**
* Needs to be called if keepAlive is set to true in request options.
@@ -2652,14 +2763,22 @@ class HttpClient {
* @param data
*/
requestRaw(info, data) {
- return new Promise((resolve, reject) => {
- let callbackForResult = function (err, res) {
- if (err) {
- reject(err);
+ return __awaiter(this, void 0, void 0, function* () {
+ return new Promise((resolve, reject) => {
+ function callbackForResult(err, res) {
+ if (err) {
+ reject(err);
+ }
+ else if (!res) {
+ // If `err` is not passed, then `res` must be passed.
+ reject(new Error('Unknown error'));
+ }
+ else {
+ resolve(res);
+ }
}
- resolve(res);
- };
- this.requestRawWithCallback(info, data, callbackForResult);
+ this.requestRawWithCallback(info, data, callbackForResult);
+ });
});
}
/**
@@ -2669,21 +2788,24 @@ class HttpClient {
* @param onResult
*/
requestRawWithCallback(info, data, onResult) {
- let socket;
if (typeof data === 'string') {
+ if (!info.options.headers) {
+ info.options.headers = {};
+ }
info.options.headers['Content-Length'] = Buffer.byteLength(data, 'utf8');
}
let callbackCalled = false;
- let handleResult = (err, res) => {
+ function handleResult(err, res) {
if (!callbackCalled) {
callbackCalled = true;
onResult(err, res);
}
- };
- let req = info.httpModule.request(info.options, (msg) => {
- let res = new HttpClientResponse(msg);
- handleResult(null, res);
+ }
+ const req = info.httpModule.request(info.options, (msg) => {
+ const res = new HttpClientResponse(msg);
+ handleResult(undefined, res);
});
+ let socket;
req.on('socket', sock => {
socket = sock;
});
@@ -2692,12 +2814,12 @@ class HttpClient {
if (socket) {
socket.end();
}
- handleResult(new Error('Request timeout: ' + info.options.path), null);
+ handleResult(new Error(`Request timeout: ${info.options.path}`));
});
req.on('error', function (err) {
// err has statusCode property
// res should have headers
- handleResult(err, null);
+ handleResult(err);
});
if (data && typeof data === 'string') {
req.write(data, 'utf8');
@@ -2718,7 +2840,7 @@ class HttpClient {
* @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
*/
getAgent(serverUrl) {
- let parsedUrl = new URL(serverUrl);
+ const parsedUrl = new URL(serverUrl);
return this._getAgent(parsedUrl);
}
_prepareRequest(method, requestUrl, headers) {
@@ -2742,21 +2864,19 @@ class HttpClient {
info.options.agent = this._getAgent(info.parsedUrl);
// gives handlers an opportunity to participate
if (this.handlers) {
- this.handlers.forEach(handler => {
+ for (const handler of this.handlers) {
handler.prepareRequest(info.options);
- });
+ }
}
return info;
}
_mergeHeaders(headers) {
- const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
if (this.requestOptions && this.requestOptions.headers) {
- return Object.assign({}, lowercaseKeys(this.requestOptions.headers), lowercaseKeys(headers));
+ return Object.assign({}, lowercaseKeys(this.requestOptions.headers), lowercaseKeys(headers || {}));
}
return lowercaseKeys(headers || {});
}
_getExistingOrDefaultHeader(additionalHeaders, header, _default) {
- const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
let clientHeader;
if (this.requestOptions && this.requestOptions.headers) {
clientHeader = lowercaseKeys(this.requestOptions.headers)[header];
@@ -2765,8 +2885,8 @@ class HttpClient {
}
_getAgent(parsedUrl) {
let agent;
- let proxyUrl = pm.getProxyUrl(parsedUrl);
- let useProxy = proxyUrl && proxyUrl.hostname;
+ const proxyUrl = pm.getProxyUrl(parsedUrl);
+ const useProxy = proxyUrl && proxyUrl.hostname;
if (this._keepAlive && useProxy) {
agent = this._proxyAgent;
}
@@ -2774,29 +2894,22 @@ class HttpClient {
agent = this._agent;
}
// if agent is already assigned use that agent.
- if (!!agent) {
+ if (agent) {
return agent;
}
const usingSsl = parsedUrl.protocol === 'https:';
let maxSockets = 100;
- if (!!this.requestOptions) {
+ if (this.requestOptions) {
maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets;
}
- if (useProxy) {
- // If using proxy, need tunnel
- if (!tunnel) {
- tunnel = __nccwpck_require__(4294);
- }
+ // This is `useProxy` again, but we need to check `proxyURl` directly for TypeScripts's flow analysis.
+ if (proxyUrl && proxyUrl.hostname) {
const agentOptions = {
- maxSockets: maxSockets,
+ maxSockets,
keepAlive: this._keepAlive,
- proxy: {
- ...((proxyUrl.username || proxyUrl.password) && {
- proxyAuth: `${proxyUrl.username}:${proxyUrl.password}`
- }),
- host: proxyUrl.hostname,
- port: proxyUrl.port
- }
+ proxy: Object.assign(Object.assign({}, ((proxyUrl.username || proxyUrl.password) && {
+ proxyAuth: `${proxyUrl.username}:${proxyUrl.password}`
+ })), { host: proxyUrl.hostname, port: proxyUrl.port })
};
let tunnelAgent;
const overHttps = proxyUrl.protocol === 'https:';
@@ -2811,7 +2924,7 @@ class HttpClient {
}
// if reusing agent across request and tunneling agent isn't assigned create a new agent
if (this._keepAlive && !agent) {
- const options = { keepAlive: this._keepAlive, maxSockets: maxSockets };
+ const options = { keepAlive: this._keepAlive, maxSockets };
agent = usingSsl ? new https.Agent(options) : new http.Agent(options);
this._agent = agent;
}
@@ -2830,109 +2943,117 @@ class HttpClient {
return agent;
}
_performExponentialBackoff(retryNumber) {
- retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber);
- const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber);
- return new Promise(resolve => setTimeout(() => resolve(), ms));
+ return __awaiter(this, void 0, void 0, function* () {
+ retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber);
+ const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber);
+ return new Promise(resolve => setTimeout(() => resolve(), ms));
+ });
}
- static dateTimeDeserializer(key, value) {
- if (typeof value === 'string') {
- let a = new Date(value);
- if (!isNaN(a.valueOf())) {
- return a;
- }
- }
- return value;
- }
- async _processResponse(res, options) {
- return new Promise(async (resolve, reject) => {
- const statusCode = res.message.statusCode;
- const response = {
- statusCode: statusCode,
- result: null,
- headers: {}
- };
- // not found leads to null obj returned
- if (statusCode == HttpCodes.NotFound) {
- resolve(response);
- }
- let obj;
- let contents;
- // get the result from the body
- try {
- contents = await res.readBody();
- if (contents && contents.length > 0) {
- if (options && options.deserializeDates) {
- obj = JSON.parse(contents, HttpClient.dateTimeDeserializer);
+ _processResponse(res, options) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
+ const statusCode = res.message.statusCode || 0;
+ const response = {
+ statusCode,
+ result: null,
+ headers: {}
+ };
+ // not found leads to null obj returned
+ if (statusCode === HttpCodes.NotFound) {
+ resolve(response);
+ }
+ // get the result from the body
+ function dateTimeDeserializer(key, value) {
+ if (typeof value === 'string') {
+ const a = new Date(value);
+ if (!isNaN(a.valueOf())) {
+ return a;
+ }
+ }
+ return value;
+ }
+ let obj;
+ let contents;
+ try {
+ contents = yield res.readBody();
+ if (contents && contents.length > 0) {
+ if (options && options.deserializeDates) {
+ obj = JSON.parse(contents, dateTimeDeserializer);
+ }
+ else {
+ obj = JSON.parse(contents);
+ }
+ response.result = obj;
+ }
+ response.headers = res.message.headers;
+ }
+ catch (err) {
+ // Invalid resource (contents not json); leaving result obj null
+ }
+ // note that 3xx redirects are handled by the http layer.
+ if (statusCode > 299) {
+ let msg;
+ // if exception/error in body, attempt to get better error
+ if (obj && obj.message) {
+ msg = obj.message;
+ }
+ else if (contents && contents.length > 0) {
+ // it may be the case that the exception is in the body message as string
+ msg = contents;
}
else {
- obj = JSON.parse(contents);
+ msg = `Failed request: (${statusCode})`;
}
- response.result = obj;
- }
- response.headers = res.message.headers;
- }
- catch (err) {
- // Invalid resource (contents not json); leaving result obj null
- }
- // note that 3xx redirects are handled by the http layer.
- if (statusCode > 299) {
- let msg;
- // if exception/error in body, attempt to get better error
- if (obj && obj.message) {
- msg = obj.message;
- }
- else if (contents && contents.length > 0) {
- // it may be the case that the exception is in the body message as string
- msg = contents;
+ const err = new HttpClientError(msg, statusCode);
+ err.result = response.result;
+ reject(err);
}
else {
- msg = 'Failed request: (' + statusCode + ')';
+ resolve(response);
}
- let err = new HttpClientError(msg, statusCode);
- err.result = response.result;
- reject(err);
- }
- else {
- resolve(response);
- }
+ }));
});
}
}
exports.HttpClient = HttpClient;
-
+const lowercaseKeys = (obj) => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
+//# sourceMappingURL=index.js.map
/***/ }),
-/***/ 7326:
+/***/ 4977:
/***/ ((__unused_webpack_module, exports) => {
"use strict";
Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.checkBypass = exports.getProxyUrl = void 0;
function getProxyUrl(reqUrl) {
- let usingSsl = reqUrl.protocol === 'https:';
- let proxyUrl;
+ const usingSsl = reqUrl.protocol === 'https:';
if (checkBypass(reqUrl)) {
- return proxyUrl;
+ return undefined;
}
- let proxyVar;
- if (usingSsl) {
- proxyVar = process.env['https_proxy'] || process.env['HTTPS_PROXY'];
+ const proxyVar = (() => {
+ if (usingSsl) {
+ return process.env['https_proxy'] || process.env['HTTPS_PROXY'];
+ }
+ else {
+ return process.env['http_proxy'] || process.env['HTTP_PROXY'];
+ }
+ })();
+ if (proxyVar) {
+ return new URL(proxyVar);
}
else {
- proxyVar = process.env['http_proxy'] || process.env['HTTP_PROXY'];
+ return undefined;
}
- if (proxyVar) {
- proxyUrl = new URL(proxyVar);
- }
- return proxyUrl;
}
exports.getProxyUrl = getProxyUrl;
function checkBypass(reqUrl) {
if (!reqUrl.hostname) {
return false;
}
- let noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || '';
+ const noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || '';
if (!noProxy) {
return false;
}
@@ -2948,12 +3069,12 @@ function checkBypass(reqUrl) {
reqPort = 443;
}
// Format the request hostname and hostname with port
- let upperReqHosts = [reqUrl.hostname.toUpperCase()];
+ const upperReqHosts = [reqUrl.hostname.toUpperCase()];
if (typeof reqPort === 'number') {
upperReqHosts.push(`${upperReqHosts[0]}:${reqPort}`);
}
// Compare request host against noproxy
- for (let upperNoProxyItem of noProxy
+ for (const upperNoProxyItem of noProxy
.split(',')
.map(x => x.trim().toUpperCase())
.filter(x => x)) {
@@ -2964,7 +3085,7 @@ function checkBypass(reqUrl) {
return false;
}
exports.checkBypass = checkBypass;
-
+//# sourceMappingURL=proxy.js.map
/***/ }),
@@ -57624,19 +57745,11 @@ function saveCache(packageManager) {
core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`);
return;
}
- try {
- yield cache.saveCache(cachePaths, primaryKey);
- core.info(`Cache saved with the key: ${primaryKey}`);
- }
- catch (error) {
- const err = error;
- if (err.name === cache.ReserveCacheError.name) {
- core.info(err.message);
- }
- else {
- throw error;
- }
+ const cacheId = yield cache.saveCache(cachePaths, primaryKey);
+ if (cacheId == -1) {
+ return;
}
+ core.info(`Cache saved with the key: ${primaryKey}`);
});
}
function isCacheDirectoryExists(cacheDirectory) {
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 3c417588..abe42a7c 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -90,17 +90,18 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
checkKey(key);
}
const compressionMethod = yield utils.getCompressionMethod();
- // path are needed to compute version
- const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
- compressionMethod
- });
- if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
- // Cache not found
- return undefined;
- }
- const archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
- core.debug(`Archive Path: ${archivePath}`);
+ let archivePath = '';
try {
+ // path are needed to compute version
+ const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
+ compressionMethod
+ });
+ if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
+ // Cache not found
+ return undefined;
+ }
+ archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
+ core.debug(`Archive Path: ${archivePath}`);
// Download the cache from the cache entry
yield cacheHttpClient.downloadCache(cacheEntry.archiveLocation, archivePath, options);
if (core.isDebug()) {
@@ -110,6 +111,17 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
core.info(`Cache Size: ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B)`);
yield tar_1.extractTar(archivePath, compressionMethod);
core.info('Cache restored successfully');
+ return cacheEntry.cacheKey;
+ }
+ catch (error) {
+ const typedError = error;
+ if (typedError.name === ValidationError.name) {
+ throw error;
+ }
+ else {
+ // Supress all non-validation cache related errors because caching should be optional
+ core.warning(`Failed to restore: ${error.message}`);
+ }
}
finally {
// Try to delete the archive to save space
@@ -120,7 +132,7 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
core.debug(`Failed to delete archive: ${error}`);
}
}
- return cacheEntry.cacheKey;
+ return undefined;
});
}
exports.restoreCache = restoreCache;
@@ -138,10 +150,13 @@ function saveCache(paths, key, options) {
checkPaths(paths);
checkKey(key);
const compressionMethod = yield utils.getCompressionMethod();
- let cacheId = null;
+ let cacheId = -1;
const cachePaths = yield utils.resolvePaths(paths);
core.debug('Cache Paths:');
core.debug(`${JSON.stringify(cachePaths)}`);
+ if (cachePaths.length === 0) {
+ throw new Error(`Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.`);
+ }
const archiveFolder = yield utils.createTempDirectory();
const archivePath = path.join(archiveFolder, utils.getCacheFileName(compressionMethod));
core.debug(`Archive Path: ${archivePath}`);
@@ -174,6 +189,18 @@ function saveCache(paths, key, options) {
core.debug(`Saving Cache (ID: ${cacheId})`);
yield cacheHttpClient.saveCache(cacheId, archivePath, options);
}
+ catch (error) {
+ const typedError = error;
+ if (typedError.name === ValidationError.name) {
+ throw error;
+ }
+ else if (typedError.name === ReserveCacheError.name) {
+ core.info(`Failed to save: ${typedError.message}`);
+ }
+ else {
+ core.warning(`Failed to save: ${typedError.message}`);
+ }
+ }
finally {
// Try to delete the archive to save space
try {
@@ -214,8 +241,8 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(7320);
-const auth_1 = __nccwpck_require__(7093);
+const http_client_1 = __nccwpck_require__(1825);
+const auth_1 = __nccwpck_require__(2001);
const crypto = __importStar(__nccwpck_require__(6113));
const fs = __importStar(__nccwpck_require__(7147));
const url_1 = __nccwpck_require__(7310);
@@ -647,7 +674,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(7320);
+const http_client_1 = __nccwpck_require__(1825);
const storage_blob_1 = __nccwpck_require__(4100);
const buffer = __importStar(__nccwpck_require__(4300));
const fs = __importStar(__nccwpck_require__(7147));
@@ -885,7 +912,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(7320);
+const http_client_1 = __nccwpck_require__(1825);
const constants_1 = __nccwpck_require__(8840);
function isSuccessStatusCode(statusCode) {
if (!statusCode) {
@@ -962,7 +989,7 @@ function retryTypedResponse(name, method, maxAttempts = constants_1.DefaultRetry
return __awaiter(this, void 0, void 0, function* () {
return yield retry(name, method, (response) => response.statusCode, maxAttempts, delay,
// If the error object contains the statusCode property, extract it and return
- // an ITypedResponse so it can be processed by the retry logic.
+ // an TypedResponse so it can be processed by the retry logic.
(error) => {
if (error instanceof http_client_1.HttpClientError) {
return {
@@ -1120,6 +1147,8 @@ function createTar(archiveFolder, sourceDirectories, compressionMethod) {
...getCompressionProgram(),
'-cf',
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
+ '--exclude',
+ cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'-P',
'-C',
workingDirectory.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
@@ -2292,28 +2321,41 @@ exports.SearchState = SearchState;
/***/ }),
-/***/ 7093:
-/***/ ((__unused_webpack_module, exports) => {
+/***/ 2001:
+/***/ (function(__unused_webpack_module, exports) {
"use strict";
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.PersonalAccessTokenCredentialHandler = exports.BearerCredentialHandler = exports.BasicCredentialHandler = void 0;
class BasicCredentialHandler {
constructor(username, password) {
this.username = username;
this.password = password;
}
prepareRequest(options) {
- options.headers['Authorization'] =
- 'Basic ' +
- Buffer.from(this.username + ':' + this.password).toString('base64');
+ if (!options.headers) {
+ throw Error('The request has no headers');
+ }
+ options.headers['Authorization'] = `Basic ${Buffer.from(`${this.username}:${this.password}`).toString('base64')}`;
}
// This handler cannot handle 401
- canHandleAuthentication(response) {
+ canHandleAuthentication() {
return false;
}
- handleAuthentication(httpClient, requestInfo, objs) {
- return null;
+ handleAuthentication() {
+ return __awaiter(this, void 0, void 0, function* () {
+ throw new Error('not implemented');
+ });
}
}
exports.BasicCredentialHandler = BasicCredentialHandler;
@@ -2324,14 +2366,19 @@ class BearerCredentialHandler {
// currently implements pre-authorization
// TODO: support preAuth = false where it hooks on 401
prepareRequest(options) {
- options.headers['Authorization'] = 'Bearer ' + this.token;
+ if (!options.headers) {
+ throw Error('The request has no headers');
+ }
+ options.headers['Authorization'] = `Bearer ${this.token}`;
}
// This handler cannot handle 401
- canHandleAuthentication(response) {
+ canHandleAuthentication() {
return false;
}
- handleAuthentication(httpClient, requestInfo, objs) {
- return null;
+ handleAuthentication() {
+ return __awaiter(this, void 0, void 0, function* () {
+ throw new Error('not implemented');
+ });
}
}
exports.BearerCredentialHandler = BearerCredentialHandler;
@@ -2342,32 +2389,66 @@ class PersonalAccessTokenCredentialHandler {
// currently implements pre-authorization
// TODO: support preAuth = false where it hooks on 401
prepareRequest(options) {
- options.headers['Authorization'] =
- 'Basic ' + Buffer.from('PAT:' + this.token).toString('base64');
+ if (!options.headers) {
+ throw Error('The request has no headers');
+ }
+ options.headers['Authorization'] = `Basic ${Buffer.from(`PAT:${this.token}`).toString('base64')}`;
}
// This handler cannot handle 401
- canHandleAuthentication(response) {
+ canHandleAuthentication() {
return false;
}
- handleAuthentication(httpClient, requestInfo, objs) {
- return null;
+ handleAuthentication() {
+ return __awaiter(this, void 0, void 0, function* () {
+ throw new Error('not implemented');
+ });
}
}
exports.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHandler;
-
+//# sourceMappingURL=auth.js.map
/***/ }),
-/***/ 7320:
-/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
+/***/ 1825:
+/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
"use strict";
+/* eslint-disable @typescript-eslint/no-explicit-any */
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
Object.defineProperty(exports, "__esModule", ({ value: true }));
-const http = __nccwpck_require__(3685);
-const https = __nccwpck_require__(5687);
-const pm = __nccwpck_require__(7326);
-let tunnel;
+exports.HttpClient = exports.isHttps = exports.HttpClientResponse = exports.HttpClientError = exports.getProxyUrl = exports.MediaTypes = exports.Headers = exports.HttpCodes = void 0;
+const http = __importStar(__nccwpck_require__(3685));
+const https = __importStar(__nccwpck_require__(5687));
+const pm = __importStar(__nccwpck_require__(4977));
+const tunnel = __importStar(__nccwpck_require__(4294));
var HttpCodes;
(function (HttpCodes) {
HttpCodes[HttpCodes["OK"] = 200] = "OK";
@@ -2412,7 +2493,7 @@ var MediaTypes;
* @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
*/
function getProxyUrl(serverUrl) {
- let proxyUrl = pm.getProxyUrl(new URL(serverUrl));
+ const proxyUrl = pm.getProxyUrl(new URL(serverUrl));
return proxyUrl ? proxyUrl.href : '';
}
exports.getProxyUrl = getProxyUrl;
@@ -2445,20 +2526,22 @@ class HttpClientResponse {
this.message = message;
}
readBody() {
- return new Promise(async (resolve, reject) => {
- let output = Buffer.alloc(0);
- this.message.on('data', (chunk) => {
- output = Buffer.concat([output, chunk]);
- });
- this.message.on('end', () => {
- resolve(output.toString());
- });
+ return __awaiter(this, void 0, void 0, function* () {
+ return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
+ let output = Buffer.alloc(0);
+ this.message.on('data', (chunk) => {
+ output = Buffer.concat([output, chunk]);
+ });
+ this.message.on('end', () => {
+ resolve(output.toString());
+ });
+ }));
});
}
}
exports.HttpClientResponse = HttpClientResponse;
function isHttps(requestUrl) {
- let parsedUrl = new URL(requestUrl);
+ const parsedUrl = new URL(requestUrl);
return parsedUrl.protocol === 'https:';
}
exports.isHttps = isHttps;
@@ -2501,141 +2584,169 @@ class HttpClient {
}
}
options(requestUrl, additionalHeaders) {
- return this.request('OPTIONS', requestUrl, null, additionalHeaders || {});
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('OPTIONS', requestUrl, null, additionalHeaders || {});
+ });
}
get(requestUrl, additionalHeaders) {
- return this.request('GET', requestUrl, null, additionalHeaders || {});
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('GET', requestUrl, null, additionalHeaders || {});
+ });
}
del(requestUrl, additionalHeaders) {
- return this.request('DELETE', requestUrl, null, additionalHeaders || {});
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('DELETE', requestUrl, null, additionalHeaders || {});
+ });
}
post(requestUrl, data, additionalHeaders) {
- return this.request('POST', requestUrl, data, additionalHeaders || {});
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('POST', requestUrl, data, additionalHeaders || {});
+ });
}
patch(requestUrl, data, additionalHeaders) {
- return this.request('PATCH', requestUrl, data, additionalHeaders || {});
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('PATCH', requestUrl, data, additionalHeaders || {});
+ });
}
put(requestUrl, data, additionalHeaders) {
- return this.request('PUT', requestUrl, data, additionalHeaders || {});
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('PUT', requestUrl, data, additionalHeaders || {});
+ });
}
head(requestUrl, additionalHeaders) {
- return this.request('HEAD', requestUrl, null, additionalHeaders || {});
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('HEAD', requestUrl, null, additionalHeaders || {});
+ });
}
sendStream(verb, requestUrl, stream, additionalHeaders) {
- return this.request(verb, requestUrl, stream, additionalHeaders);
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request(verb, requestUrl, stream, additionalHeaders);
+ });
}
/**
* Gets a typed object from an endpoint
* Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise
*/
- async getJson(requestUrl, additionalHeaders = {}) {
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- let res = await this.get(requestUrl, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
+ getJson(requestUrl, additionalHeaders = {}) {
+ return __awaiter(this, void 0, void 0, function* () {
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ const res = yield this.get(requestUrl, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ });
}
- async postJson(requestUrl, obj, additionalHeaders = {}) {
- let data = JSON.stringify(obj, null, 2);
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
- let res = await this.post(requestUrl, data, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
+ postJson(requestUrl, obj, additionalHeaders = {}) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const data = JSON.stringify(obj, null, 2);
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
+ const res = yield this.post(requestUrl, data, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ });
}
- async putJson(requestUrl, obj, additionalHeaders = {}) {
- let data = JSON.stringify(obj, null, 2);
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
- let res = await this.put(requestUrl, data, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
+ putJson(requestUrl, obj, additionalHeaders = {}) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const data = JSON.stringify(obj, null, 2);
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
+ const res = yield this.put(requestUrl, data, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ });
}
- async patchJson(requestUrl, obj, additionalHeaders = {}) {
- let data = JSON.stringify(obj, null, 2);
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
- let res = await this.patch(requestUrl, data, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
+ patchJson(requestUrl, obj, additionalHeaders = {}) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const data = JSON.stringify(obj, null, 2);
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
+ const res = yield this.patch(requestUrl, data, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ });
}
/**
* Makes a raw http request.
* All other methods such as get, post, patch, and request ultimately call this.
* Prefer get, del, post and patch
*/
- async request(verb, requestUrl, data, headers) {
- if (this._disposed) {
- throw new Error('Client has already been disposed.');
- }
- let parsedUrl = new URL(requestUrl);
- let info = this._prepareRequest(verb, parsedUrl, headers);
- // Only perform retries on reads since writes may not be idempotent.
- let maxTries = this._allowRetries && RetryableHttpVerbs.indexOf(verb) != -1
- ? this._maxRetries + 1
- : 1;
- let numTries = 0;
- let response;
- while (numTries < maxTries) {
- response = await this.requestRaw(info, data);
- // Check if it's an authentication challenge
- if (response &&
- response.message &&
- response.message.statusCode === HttpCodes.Unauthorized) {
- let authenticationHandler;
- for (let i = 0; i < this.handlers.length; i++) {
- if (this.handlers[i].canHandleAuthentication(response)) {
- authenticationHandler = this.handlers[i];
- break;
- }
- }
- if (authenticationHandler) {
- return authenticationHandler.handleAuthentication(this, info, data);
- }
- else {
- // We have received an unauthorized response but have no handlers to handle it.
- // Let the response return to the caller.
- return response;
- }
+ request(verb, requestUrl, data, headers) {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (this._disposed) {
+ throw new Error('Client has already been disposed.');
}
- let redirectsRemaining = this._maxRedirects;
- while (HttpRedirectCodes.indexOf(response.message.statusCode) != -1 &&
- this._allowRedirects &&
- redirectsRemaining > 0) {
- const redirectUrl = response.message.headers['location'];
- if (!redirectUrl) {
- // if there's no location to redirect to, we won't
- break;
- }
- let parsedRedirectUrl = new URL(redirectUrl);
- if (parsedUrl.protocol == 'https:' &&
- parsedUrl.protocol != parsedRedirectUrl.protocol &&
- !this._allowRedirectDowngrade) {
- throw new Error('Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.');
- }
- // we need to finish reading the response before reassigning response
- // which will leak the open socket.
- await response.readBody();
- // strip authorization header if redirected to a different hostname
- if (parsedRedirectUrl.hostname !== parsedUrl.hostname) {
- for (let header in headers) {
- // header names are case insensitive
- if (header.toLowerCase() === 'authorization') {
- delete headers[header];
+ const parsedUrl = new URL(requestUrl);
+ let info = this._prepareRequest(verb, parsedUrl, headers);
+ // Only perform retries on reads since writes may not be idempotent.
+ const maxTries = this._allowRetries && RetryableHttpVerbs.includes(verb)
+ ? this._maxRetries + 1
+ : 1;
+ let numTries = 0;
+ let response;
+ do {
+ response = yield this.requestRaw(info, data);
+ // Check if it's an authentication challenge
+ if (response &&
+ response.message &&
+ response.message.statusCode === HttpCodes.Unauthorized) {
+ let authenticationHandler;
+ for (const handler of this.handlers) {
+ if (handler.canHandleAuthentication(response)) {
+ authenticationHandler = handler;
+ break;
}
}
+ if (authenticationHandler) {
+ return authenticationHandler.handleAuthentication(this, info, data);
+ }
+ else {
+ // We have received an unauthorized response but have no handlers to handle it.
+ // Let the response return to the caller.
+ return response;
+ }
}
- // let's make the request with the new redirectUrl
- info = this._prepareRequest(verb, parsedRedirectUrl, headers);
- response = await this.requestRaw(info, data);
- redirectsRemaining--;
- }
- if (HttpResponseRetryCodes.indexOf(response.message.statusCode) == -1) {
- // If not a retry code, return immediately instead of retrying
- return response;
- }
- numTries += 1;
- if (numTries < maxTries) {
- await response.readBody();
- await this._performExponentialBackoff(numTries);
- }
- }
- return response;
+ let redirectsRemaining = this._maxRedirects;
+ while (response.message.statusCode &&
+ HttpRedirectCodes.includes(response.message.statusCode) &&
+ this._allowRedirects &&
+ redirectsRemaining > 0) {
+ const redirectUrl = response.message.headers['location'];
+ if (!redirectUrl) {
+ // if there's no location to redirect to, we won't
+ break;
+ }
+ const parsedRedirectUrl = new URL(redirectUrl);
+ if (parsedUrl.protocol === 'https:' &&
+ parsedUrl.protocol !== parsedRedirectUrl.protocol &&
+ !this._allowRedirectDowngrade) {
+ throw new Error('Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.');
+ }
+ // we need to finish reading the response before reassigning response
+ // which will leak the open socket.
+ yield response.readBody();
+ // strip authorization header if redirected to a different hostname
+ if (parsedRedirectUrl.hostname !== parsedUrl.hostname) {
+ for (const header in headers) {
+ // header names are case insensitive
+ if (header.toLowerCase() === 'authorization') {
+ delete headers[header];
+ }
+ }
+ }
+ // let's make the request with the new redirectUrl
+ info = this._prepareRequest(verb, parsedRedirectUrl, headers);
+ response = yield this.requestRaw(info, data);
+ redirectsRemaining--;
+ }
+ if (!response.message.statusCode ||
+ !HttpResponseRetryCodes.includes(response.message.statusCode)) {
+ // If not a retry code, return immediately instead of retrying
+ return response;
+ }
+ numTries += 1;
+ if (numTries < maxTries) {
+ yield response.readBody();
+ yield this._performExponentialBackoff(numTries);
+ }
+ } while (numTries < maxTries);
+ return response;
+ });
}
/**
* Needs to be called if keepAlive is set to true in request options.
@@ -2652,14 +2763,22 @@ class HttpClient {
* @param data
*/
requestRaw(info, data) {
- return new Promise((resolve, reject) => {
- let callbackForResult = function (err, res) {
- if (err) {
- reject(err);
+ return __awaiter(this, void 0, void 0, function* () {
+ return new Promise((resolve, reject) => {
+ function callbackForResult(err, res) {
+ if (err) {
+ reject(err);
+ }
+ else if (!res) {
+ // If `err` is not passed, then `res` must be passed.
+ reject(new Error('Unknown error'));
+ }
+ else {
+ resolve(res);
+ }
}
- resolve(res);
- };
- this.requestRawWithCallback(info, data, callbackForResult);
+ this.requestRawWithCallback(info, data, callbackForResult);
+ });
});
}
/**
@@ -2669,21 +2788,24 @@ class HttpClient {
* @param onResult
*/
requestRawWithCallback(info, data, onResult) {
- let socket;
if (typeof data === 'string') {
+ if (!info.options.headers) {
+ info.options.headers = {};
+ }
info.options.headers['Content-Length'] = Buffer.byteLength(data, 'utf8');
}
let callbackCalled = false;
- let handleResult = (err, res) => {
+ function handleResult(err, res) {
if (!callbackCalled) {
callbackCalled = true;
onResult(err, res);
}
- };
- let req = info.httpModule.request(info.options, (msg) => {
- let res = new HttpClientResponse(msg);
- handleResult(null, res);
+ }
+ const req = info.httpModule.request(info.options, (msg) => {
+ const res = new HttpClientResponse(msg);
+ handleResult(undefined, res);
});
+ let socket;
req.on('socket', sock => {
socket = sock;
});
@@ -2692,12 +2814,12 @@ class HttpClient {
if (socket) {
socket.end();
}
- handleResult(new Error('Request timeout: ' + info.options.path), null);
+ handleResult(new Error(`Request timeout: ${info.options.path}`));
});
req.on('error', function (err) {
// err has statusCode property
// res should have headers
- handleResult(err, null);
+ handleResult(err);
});
if (data && typeof data === 'string') {
req.write(data, 'utf8');
@@ -2718,7 +2840,7 @@ class HttpClient {
* @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
*/
getAgent(serverUrl) {
- let parsedUrl = new URL(serverUrl);
+ const parsedUrl = new URL(serverUrl);
return this._getAgent(parsedUrl);
}
_prepareRequest(method, requestUrl, headers) {
@@ -2742,21 +2864,19 @@ class HttpClient {
info.options.agent = this._getAgent(info.parsedUrl);
// gives handlers an opportunity to participate
if (this.handlers) {
- this.handlers.forEach(handler => {
+ for (const handler of this.handlers) {
handler.prepareRequest(info.options);
- });
+ }
}
return info;
}
_mergeHeaders(headers) {
- const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
if (this.requestOptions && this.requestOptions.headers) {
- return Object.assign({}, lowercaseKeys(this.requestOptions.headers), lowercaseKeys(headers));
+ return Object.assign({}, lowercaseKeys(this.requestOptions.headers), lowercaseKeys(headers || {}));
}
return lowercaseKeys(headers || {});
}
_getExistingOrDefaultHeader(additionalHeaders, header, _default) {
- const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
let clientHeader;
if (this.requestOptions && this.requestOptions.headers) {
clientHeader = lowercaseKeys(this.requestOptions.headers)[header];
@@ -2765,8 +2885,8 @@ class HttpClient {
}
_getAgent(parsedUrl) {
let agent;
- let proxyUrl = pm.getProxyUrl(parsedUrl);
- let useProxy = proxyUrl && proxyUrl.hostname;
+ const proxyUrl = pm.getProxyUrl(parsedUrl);
+ const useProxy = proxyUrl && proxyUrl.hostname;
if (this._keepAlive && useProxy) {
agent = this._proxyAgent;
}
@@ -2774,29 +2894,22 @@ class HttpClient {
agent = this._agent;
}
// if agent is already assigned use that agent.
- if (!!agent) {
+ if (agent) {
return agent;
}
const usingSsl = parsedUrl.protocol === 'https:';
let maxSockets = 100;
- if (!!this.requestOptions) {
+ if (this.requestOptions) {
maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets;
}
- if (useProxy) {
- // If using proxy, need tunnel
- if (!tunnel) {
- tunnel = __nccwpck_require__(4294);
- }
+ // This is `useProxy` again, but we need to check `proxyURl` directly for TypeScripts's flow analysis.
+ if (proxyUrl && proxyUrl.hostname) {
const agentOptions = {
- maxSockets: maxSockets,
+ maxSockets,
keepAlive: this._keepAlive,
- proxy: {
- ...((proxyUrl.username || proxyUrl.password) && {
- proxyAuth: `${proxyUrl.username}:${proxyUrl.password}`
- }),
- host: proxyUrl.hostname,
- port: proxyUrl.port
- }
+ proxy: Object.assign(Object.assign({}, ((proxyUrl.username || proxyUrl.password) && {
+ proxyAuth: `${proxyUrl.username}:${proxyUrl.password}`
+ })), { host: proxyUrl.hostname, port: proxyUrl.port })
};
let tunnelAgent;
const overHttps = proxyUrl.protocol === 'https:';
@@ -2811,7 +2924,7 @@ class HttpClient {
}
// if reusing agent across request and tunneling agent isn't assigned create a new agent
if (this._keepAlive && !agent) {
- const options = { keepAlive: this._keepAlive, maxSockets: maxSockets };
+ const options = { keepAlive: this._keepAlive, maxSockets };
agent = usingSsl ? new https.Agent(options) : new http.Agent(options);
this._agent = agent;
}
@@ -2830,109 +2943,117 @@ class HttpClient {
return agent;
}
_performExponentialBackoff(retryNumber) {
- retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber);
- const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber);
- return new Promise(resolve => setTimeout(() => resolve(), ms));
+ return __awaiter(this, void 0, void 0, function* () {
+ retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber);
+ const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber);
+ return new Promise(resolve => setTimeout(() => resolve(), ms));
+ });
}
- static dateTimeDeserializer(key, value) {
- if (typeof value === 'string') {
- let a = new Date(value);
- if (!isNaN(a.valueOf())) {
- return a;
- }
- }
- return value;
- }
- async _processResponse(res, options) {
- return new Promise(async (resolve, reject) => {
- const statusCode = res.message.statusCode;
- const response = {
- statusCode: statusCode,
- result: null,
- headers: {}
- };
- // not found leads to null obj returned
- if (statusCode == HttpCodes.NotFound) {
- resolve(response);
- }
- let obj;
- let contents;
- // get the result from the body
- try {
- contents = await res.readBody();
- if (contents && contents.length > 0) {
- if (options && options.deserializeDates) {
- obj = JSON.parse(contents, HttpClient.dateTimeDeserializer);
+ _processResponse(res, options) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
+ const statusCode = res.message.statusCode || 0;
+ const response = {
+ statusCode,
+ result: null,
+ headers: {}
+ };
+ // not found leads to null obj returned
+ if (statusCode === HttpCodes.NotFound) {
+ resolve(response);
+ }
+ // get the result from the body
+ function dateTimeDeserializer(key, value) {
+ if (typeof value === 'string') {
+ const a = new Date(value);
+ if (!isNaN(a.valueOf())) {
+ return a;
+ }
+ }
+ return value;
+ }
+ let obj;
+ let contents;
+ try {
+ contents = yield res.readBody();
+ if (contents && contents.length > 0) {
+ if (options && options.deserializeDates) {
+ obj = JSON.parse(contents, dateTimeDeserializer);
+ }
+ else {
+ obj = JSON.parse(contents);
+ }
+ response.result = obj;
+ }
+ response.headers = res.message.headers;
+ }
+ catch (err) {
+ // Invalid resource (contents not json); leaving result obj null
+ }
+ // note that 3xx redirects are handled by the http layer.
+ if (statusCode > 299) {
+ let msg;
+ // if exception/error in body, attempt to get better error
+ if (obj && obj.message) {
+ msg = obj.message;
+ }
+ else if (contents && contents.length > 0) {
+ // it may be the case that the exception is in the body message as string
+ msg = contents;
}
else {
- obj = JSON.parse(contents);
+ msg = `Failed request: (${statusCode})`;
}
- response.result = obj;
- }
- response.headers = res.message.headers;
- }
- catch (err) {
- // Invalid resource (contents not json); leaving result obj null
- }
- // note that 3xx redirects are handled by the http layer.
- if (statusCode > 299) {
- let msg;
- // if exception/error in body, attempt to get better error
- if (obj && obj.message) {
- msg = obj.message;
- }
- else if (contents && contents.length > 0) {
- // it may be the case that the exception is in the body message as string
- msg = contents;
+ const err = new HttpClientError(msg, statusCode);
+ err.result = response.result;
+ reject(err);
}
else {
- msg = 'Failed request: (' + statusCode + ')';
+ resolve(response);
}
- let err = new HttpClientError(msg, statusCode);
- err.result = response.result;
- reject(err);
- }
- else {
- resolve(response);
- }
+ }));
});
}
}
exports.HttpClient = HttpClient;
-
+const lowercaseKeys = (obj) => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
+//# sourceMappingURL=index.js.map
/***/ }),
-/***/ 7326:
+/***/ 4977:
/***/ ((__unused_webpack_module, exports) => {
"use strict";
Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.checkBypass = exports.getProxyUrl = void 0;
function getProxyUrl(reqUrl) {
- let usingSsl = reqUrl.protocol === 'https:';
- let proxyUrl;
+ const usingSsl = reqUrl.protocol === 'https:';
if (checkBypass(reqUrl)) {
- return proxyUrl;
+ return undefined;
}
- let proxyVar;
- if (usingSsl) {
- proxyVar = process.env['https_proxy'] || process.env['HTTPS_PROXY'];
+ const proxyVar = (() => {
+ if (usingSsl) {
+ return process.env['https_proxy'] || process.env['HTTPS_PROXY'];
+ }
+ else {
+ return process.env['http_proxy'] || process.env['HTTP_PROXY'];
+ }
+ })();
+ if (proxyVar) {
+ return new URL(proxyVar);
}
else {
- proxyVar = process.env['http_proxy'] || process.env['HTTP_PROXY'];
+ return undefined;
}
- if (proxyVar) {
- proxyUrl = new URL(proxyVar);
- }
- return proxyUrl;
}
exports.getProxyUrl = getProxyUrl;
function checkBypass(reqUrl) {
if (!reqUrl.hostname) {
return false;
}
- let noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || '';
+ const noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || '';
if (!noProxy) {
return false;
}
@@ -2948,12 +3069,12 @@ function checkBypass(reqUrl) {
reqPort = 443;
}
// Format the request hostname and hostname with port
- let upperReqHosts = [reqUrl.hostname.toUpperCase()];
+ const upperReqHosts = [reqUrl.hostname.toUpperCase()];
if (typeof reqPort === 'number') {
upperReqHosts.push(`${upperReqHosts[0]}:${reqPort}`);
}
// Compare request host against noproxy
- for (let upperNoProxyItem of noProxy
+ for (const upperNoProxyItem of noProxy
.split(',')
.map(x => x.trim().toUpperCase())
.filter(x => x)) {
@@ -2964,7 +3085,7 @@ function checkBypass(reqUrl) {
return false;
}
exports.checkBypass = checkBypass;
-
+//# sourceMappingURL=proxy.js.map
/***/ }),
diff --git a/package-lock.json b/package-lock.json
index d009e435..34643ed2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,7 @@
"version": "4.0.0",
"license": "MIT",
"dependencies": {
- "@actions/cache": "^2.0.2",
+ "@actions/cache": "^3.0.0",
"@actions/core": "^1.2.3",
"@actions/exec": "^1.1.0",
"@actions/glob": "^0.2.0",
@@ -31,14 +31,14 @@
}
},
"node_modules/@actions/cache": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/@actions/cache/-/cache-2.0.2.tgz",
- "integrity": "sha512-K1DCaW/OtHj5mV7hI7HEXiceX3rM4Nc0iG2hfYsrkEy6GiOeqlCC/LyICrBZIRDM6+vSrS12tg1ORl4hghomBA==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@actions/cache/-/cache-3.0.0.tgz",
+ "integrity": "sha512-GL9CT1Fnu+pqs8TTB621q8Xa8Cilw2n9MwvbgMedetH7L1q2n6jY61gzbwGbKgtVbp3gVJ12aNMi4osSGXx3KQ==",
"dependencies": {
"@actions/core": "^1.2.6",
"@actions/exec": "^1.0.1",
"@actions/glob": "^0.1.0",
- "@actions/http-client": "^1.0.9",
+ "@actions/http-client": "^2.0.1",
"@actions/io": "^1.0.1",
"@azure/ms-rest-js": "^2.6.0",
"@azure/storage-blob": "^12.8.0",
@@ -56,11 +56,11 @@
}
},
"node_modules/@actions/cache/node_modules/@actions/http-client": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
- "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
+ "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"dependencies": {
- "tunnel": "0.0.6"
+ "tunnel": "^0.0.6"
}
},
"node_modules/@actions/cache/node_modules/semver": {
@@ -11337,14 +11337,14 @@
},
"dependencies": {
"@actions/cache": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/@actions/cache/-/cache-2.0.2.tgz",
- "integrity": "sha512-K1DCaW/OtHj5mV7hI7HEXiceX3rM4Nc0iG2hfYsrkEy6GiOeqlCC/LyICrBZIRDM6+vSrS12tg1ORl4hghomBA==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@actions/cache/-/cache-3.0.0.tgz",
+ "integrity": "sha512-GL9CT1Fnu+pqs8TTB621q8Xa8Cilw2n9MwvbgMedetH7L1q2n6jY61gzbwGbKgtVbp3gVJ12aNMi4osSGXx3KQ==",
"requires": {
"@actions/core": "^1.2.6",
"@actions/exec": "^1.0.1",
"@actions/glob": "^0.1.0",
- "@actions/http-client": "^1.0.9",
+ "@actions/http-client": "^2.0.1",
"@actions/io": "^1.0.1",
"@azure/ms-rest-js": "^2.6.0",
"@azure/storage-blob": "^12.8.0",
@@ -11362,11 +11362,11 @@
}
},
"@actions/http-client": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
- "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
+ "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"requires": {
- "tunnel": "0.0.6"
+ "tunnel": "^0.0.6"
}
},
"semver": {
diff --git a/package.json b/package.json
index d7d88f24..55c80f34 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
"format": "prettier --write \"{,!(node_modules)/**/}*.ts\"",
"format-check": "prettier --check \"{,!(node_modules)/**/}*.ts\"",
"release": "ncc build -o dist/setup src/setup-python.ts && ncc build -o dist/cache-save src/cache-save.ts && git add -f dist/",
- "test": "jest"
+ "test": "jest --coverage"
},
"repository": {
"type": "git",
@@ -23,7 +23,7 @@
"author": "GitHub",
"license": "MIT",
"dependencies": {
- "@actions/cache": "^2.0.2",
+ "@actions/cache": "^3.0.0",
"@actions/core": "^1.2.3",
"@actions/exec": "^1.1.0",
"@actions/glob": "^0.2.0",
diff --git a/src/cache-save.ts b/src/cache-save.ts
index 0f9d0372..6e96be12 100644
--- a/src/cache-save.ts
+++ b/src/cache-save.ts
@@ -43,17 +43,11 @@ async function saveCache(packageManager: string) {
return;
}
- try {
- await cache.saveCache(cachePaths, primaryKey);
- core.info(`Cache saved with the key: ${primaryKey}`);
- } catch (error) {
- const err = error as Error;
- if (err.name === cache.ReserveCacheError.name) {
- core.info(err.message);
- } else {
- throw error;
- }
+ const cacheId = await cache.saveCache(cachePaths, primaryKey);
+ if (cacheId == -1) {
+ return;
}
+ core.info(`Cache saved with the key: ${primaryKey}`);
}
function isCacheDirectoryExists(cacheDirectory: string[]) {
From c61bc3d08eec4fcddeff411c5e4690775e18bdb2 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Tue, 28 Jun 2022 15:40:29 +0200
Subject: [PATCH 02/77] Update licenses
---
.licenses/npm/@actions/cache.dep.yml | 2 +-
.../npm/@actions/http-client-2.0.1.dep.yml | 32 +++++++++++++++++++
2 files changed, 33 insertions(+), 1 deletion(-)
create mode 100644 .licenses/npm/@actions/http-client-2.0.1.dep.yml
diff --git a/.licenses/npm/@actions/cache.dep.yml b/.licenses/npm/@actions/cache.dep.yml
index f7aa5837..c3c245ef 100644
--- a/.licenses/npm/@actions/cache.dep.yml
+++ b/.licenses/npm/@actions/cache.dep.yml
@@ -1,6 +1,6 @@
---
name: "@actions/cache"
-version: 2.0.2
+version: 3.0.0
type: npm
summary: Actions cache lib
homepage: https://github.com/actions/toolkit/tree/main/packages/cache
diff --git a/.licenses/npm/@actions/http-client-2.0.1.dep.yml b/.licenses/npm/@actions/http-client-2.0.1.dep.yml
new file mode 100644
index 00000000..88e4e663
--- /dev/null
+++ b/.licenses/npm/@actions/http-client-2.0.1.dep.yml
@@ -0,0 +1,32 @@
+---
+name: "@actions/http-client"
+version: 2.0.1
+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: []
From a8da2a66aae3085f1d5ca820e8e5ca85120670fc Mon Sep 17 00:00:00 2001
From: Sergey Dolin
Date: Wed, 27 Apr 2022 11:28:44 +0500
Subject: [PATCH 03/77] Use /opt/hostedtoolcache as default value
AGENT_TOOLSDIRECTORY
---
dist/setup/index.js | 127 ++++++++++++++++++++++++++++++++++++++++++++
src/setup-python.ts | 15 +++---
2 files changed, 133 insertions(+), 9 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 3c417588..44f8ed5d 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -5225,10 +5225,137 @@ class ToolRunner extends events.EventEmitter {
return (this._endsWith(upperToolPath, '.CMD') ||
this._endsWith(upperToolPath, '.BAT'));
}
+<<<<<<< HEAD
_windowsQuoteCmdArg(arg) {
// for .exe, apply the normal quoting rules that libuv applies
if (!this._isCmdFile()) {
return this._uvQuoteCmdArg(arg);
+=======
+
+ const sameDirectionIncreasing =
+ (this.operator === '>=' || this.operator === '>') &&
+ (comp.operator === '>=' || comp.operator === '>')
+ const sameDirectionDecreasing =
+ (this.operator === '<=' || this.operator === '<') &&
+ (comp.operator === '<=' || comp.operator === '<')
+ const sameSemVer = this.semver.version === comp.semver.version
+ const differentDirectionsInclusive =
+ (this.operator === '>=' || this.operator === '<=') &&
+ (comp.operator === '>=' || comp.operator === '<=')
+ const oppositeDirectionsLessThan =
+ cmp(this.semver, '<', comp.semver, options) &&
+ (this.operator === '>=' || this.operator === '>') &&
+ (comp.operator === '<=' || comp.operator === '<')
+ const oppositeDirectionsGreaterThan =
+ cmp(this.semver, '>', comp.semver, options) &&
+ (this.operator === '<=' || this.operator === '<') &&
+ (comp.operator === '>=' || comp.operator === '>')
+
+ return (
+ sameDirectionIncreasing ||
+ sameDirectionDecreasing ||
+ (sameSemVer && differentDirectionsInclusive) ||
+ oppositeDirectionsLessThan ||
+ oppositeDirectionsGreaterThan
+ )
+ }
+}
+
+module.exports = Comparator
+
+const {re, t} = __webpack_require__(328)
+const cmp = __webpack_require__(752)
+const debug = __webpack_require__(548)
+const SemVer = __webpack_require__(206)
+const Range = __webpack_require__(124)
+
+
+/***/ }),
+/* 175 */
+/***/ (function(__unusedmodule, exports, __webpack_require__) {
+
+"use strict";
+
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const core = __importStar(__webpack_require__(470));
+const finder = __importStar(__webpack_require__(927));
+const finderPyPy = __importStar(__webpack_require__(847));
+const path = __importStar(__webpack_require__(622));
+const os = __importStar(__webpack_require__(87));
+const cache_factory_1 = __webpack_require__(633);
+const utils_1 = __webpack_require__(163);
+function isPyPyVersion(versionSpec) {
+ return versionSpec.startsWith('pypy-');
+}
+function cacheDependencies(cache, pythonVersion) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const cacheDependencyPath = core.getInput('cache-dependency-path') || undefined;
+ const cacheDistributor = cache_factory_1.getCacheDistributor(cache, pythonVersion, cacheDependencyPath);
+ yield cacheDistributor.restoreCache();
+ });
+}
+function run() {
+ var _a;
+ return __awaiter(this, void 0, void 0, function* () {
+ if (!((_a = process.env.AGENT_TOOLSDIRECTORY) === null || _a === void 0 ? void 0 : _a.trim())) {
+ process.env['AGENT_TOOLSDIRECTORY'] = '/opt/hostedtoolcache';
+ }
+ core.debug(`Python is expected to be installed into AGENT_TOOLSDIRECTORY=${process.env['AGENT_TOOLSDIRECTORY']}`);
+ process.env['RUNNER_TOOL_CACHE'] = process.env['AGENT_TOOLSDIRECTORY'];
+ try {
+ const version = core.getInput('python-version');
+ if (version) {
+ let pythonVersion;
+ const arch = core.getInput('architecture') || os.arch();
+ if (isPyPyVersion(version)) {
+ const installed = yield finderPyPy.findPyPyVersion(version, arch);
+ pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`;
+ core.info(`Successfully setup PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})`);
+ }
+ else {
+ const installed = yield finder.useCpythonVersion(version, arch);
+ pythonVersion = installed.version;
+ core.info(`Successfully setup ${installed.impl} (${pythonVersion})`);
+ }
+ const cache = core.getInput('cache');
+ if (cache && utils_1.isCacheFeatureAvailable()) {
+ yield cacheDependencies(cache, pythonVersion);
+ }
+ }
+ else {
+ throw new Error("there's empty python-version input");
+ }
+ const matchersPath = path.join(__dirname, '../..', '.github');
+ core.info(`##[add-matcher]${path.join(matchersPath, 'python.json')}`);
+>>>>>>> 99015f8 (Use /opt/hostedtoolcache as default value AGENT_TOOLSDIRECTORY)
}
// otherwise apply quoting rules specific to the cmd.exe command line parser.
// the libuv rules are generic and are not designed specifically for cmd.exe
diff --git a/src/setup-python.ts b/src/setup-python.ts
index 2ffeb1ad..a3dd0607 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -49,16 +49,13 @@ function resolveVersionInput(): string {
}
async function run() {
- if (process.env.AGENT_TOOLSDIRECTORY?.trim()) {
- core.debug(
- `Python is expected to be installed into AGENT_TOOLSDIRECTORY=${process.env['AGENT_TOOLSDIRECTORY']}`
- );
- process.env['RUNNER_TOOL_CACHE'] = process.env['AGENT_TOOLSDIRECTORY'];
- } else {
- core.debug(
- `Python is expected to be installed into RUNNER_TOOL_CACHE==${process.env['RUNNER_TOOL_CACHE']}`
- );
+ if (!process.env.AGENT_TOOLSDIRECTORY?.trim()) {
+ process.env['AGENT_TOOLSDIRECTORY'] = '/opt/hostedtoolcache';
}
+ core.debug(
+ `Python is expected to be installed into AGENT_TOOLSDIRECTORY=${process.env['AGENT_TOOLSDIRECTORY']}`
+ );
+ process.env['RUNNER_TOOL_CACHE'] = process.env['AGENT_TOOLSDIRECTORY'];
try {
const version = resolveVersionInput();
if (version) {
From 5ad79022bcf7697f57275899d0f60e4afbdea17d Mon Sep 17 00:00:00 2001
From: Sergey Dolin
Date: Thu, 28 Apr 2022 12:14:49 +0500
Subject: [PATCH 04/77] Change README
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index d5968fdc..bc257ab4 100644
--- a/README.md
+++ b/README.md
@@ -337,7 +337,7 @@ If you are experiencing problems while configuring Python on your self-hosted ru
### Linux
- The Python packages that are downloaded from `actions/python-versions` are originally compiled from source in `/opt/hostedtoolcache/` with the [--enable-shared](https://github.com/actions/python-versions/blob/94f04ae6806c6633c82db94c6406a16e17decd5c/builders/ubuntu-python-builder.psm1#L35) flag, which makes them non-relocatable.
-- Create an environment variable called `AGENT_TOOLSDIRECTORY` and set it to `/opt/hostedtoolcache`. This controls where the runner downloads and installs tools.
+- By default runner downloads and install the tools to `/opt/hostedtoolcache`. The environment variable called `AGENT_TOOLSDIRECTORY` can be set to change this location.
- In the same shell that your runner is using, type `export AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache`.
- A more permanent way of setting the environment variable is to create a `.env` file in the same directory as your runner and to add `AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache`. This ensures the variable is always set if your runner is configured as a service.
- Create a directory called `hostedtoolcache` inside `/opt`.
From 7199395312a0a82b9c1b42a0e147408b89071ca6 Mon Sep 17 00:00:00 2001
From: Sergey Dolin
Date: Thu, 5 May 2022 21:01:59 +0500
Subject: [PATCH 05/77] Fix dist folder
---
dist/setup/index.js | 3 ---
1 file changed, 3 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 44f8ed5d..e4c60af8 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -5350,9 +5350,6 @@ function run() {
yield cacheDependencies(cache, pythonVersion);
}
}
- else {
- throw new Error("there's empty python-version input");
- }
const matchersPath = path.join(__dirname, '../..', '.github');
core.info(`##[add-matcher]${path.join(matchersPath, 'python.json')}`);
>>>>>>> 99015f8 (Use /opt/hostedtoolcache as default value AGENT_TOOLSDIRECTORY)
From 5d9fdcab75b9ab9c36a00d14742e5d54dcbb8e42 Mon Sep 17 00:00:00 2001
From: Sergey Dolin
Date: Fri, 6 May 2022 09:09:02 +0500
Subject: [PATCH 06/77] Handle each OS in its own way
---
dist/setup/index.js | 7 +++++--
src/setup-python.ts | 7 ++++---
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index e4c60af8..06dada78 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -5325,8 +5325,11 @@ function cacheDependencies(cache, pythonVersion) {
function run() {
var _a;
return __awaiter(this, void 0, void 0, function* () {
- if (!((_a = process.env.AGENT_TOOLSDIRECTORY) === null || _a === void 0 ? void 0 : _a.trim())) {
- process.env['AGENT_TOOLSDIRECTORY'] = '/opt/hostedtoolcache';
+ if (!utils_1.IS_WINDOWS && !((_a = process.env.AGENT_TOOLSDIRECTORY) === null || _a === void 0 ? void 0 : _a.trim())) {
+ if (utils_1.IS_LINUX)
+ process.env['AGENT_TOOLSDIRECTORY'] = '/opt/hostedtoolcache';
+ else
+ process.env['AGENT_TOOLSDIRECTORY'] = '/Users/runner/hostedtoolcache';
}
core.debug(`Python is expected to be installed into AGENT_TOOLSDIRECTORY=${process.env['AGENT_TOOLSDIRECTORY']}`);
process.env['RUNNER_TOOL_CACHE'] = process.env['AGENT_TOOLSDIRECTORY'];
diff --git a/src/setup-python.ts b/src/setup-python.ts
index a3dd0607..0b1553b0 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -5,7 +5,7 @@ import * as path from 'path';
import * as os from 'os';
import fs from 'fs';
import {getCacheDistributor} from './cache-distributions/cache-factory';
-import {isCacheFeatureAvailable} from './utils';
+import {isCacheFeatureAvailable, IS_LINUX, IS_WINDOWS} from './utils';
function isPyPyVersion(versionSpec: string) {
return versionSpec.startsWith('pypy');
@@ -49,8 +49,9 @@ function resolveVersionInput(): string {
}
async function run() {
- if (!process.env.AGENT_TOOLSDIRECTORY?.trim()) {
- process.env['AGENT_TOOLSDIRECTORY'] = '/opt/hostedtoolcache';
+ if (!IS_WINDOWS && !process.env.AGENT_TOOLSDIRECTORY?.trim()) {
+ if (IS_LINUX) process.env['AGENT_TOOLSDIRECTORY'] = '/opt/hostedtoolcache';
+ else process.env['AGENT_TOOLSDIRECTORY'] = '/Users/runner/hostedtoolcache';
}
core.debug(
`Python is expected to be installed into AGENT_TOOLSDIRECTORY=${process.env['AGENT_TOOLSDIRECTORY']}`
From 958897304aea586672b0085b6b9031f928b11961 Mon Sep 17 00:00:00 2001
From: Sergey Dolin
Date: Fri, 6 May 2022 09:26:48 +0500
Subject: [PATCH 07/77] Exclude windows from the fix
---
dist/setup/index.js | 6 ++++--
src/setup-python.ts | 6 ++++--
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 06dada78..6d75cc20 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -5325,14 +5325,16 @@ function cacheDependencies(cache, pythonVersion) {
function run() {
var _a;
return __awaiter(this, void 0, void 0, function* () {
+ // According to the README windows binaries do not require to be installed
+ // in the specific location, but Mac and Linux do
if (!utils_1.IS_WINDOWS && !((_a = process.env.AGENT_TOOLSDIRECTORY) === null || _a === void 0 ? void 0 : _a.trim())) {
if (utils_1.IS_LINUX)
process.env['AGENT_TOOLSDIRECTORY'] = '/opt/hostedtoolcache';
else
process.env['AGENT_TOOLSDIRECTORY'] = '/Users/runner/hostedtoolcache';
+ process.env['RUNNER_TOOL_CACHE'] = process.env['AGENT_TOOLSDIRECTORY'];
}
- core.debug(`Python is expected to be installed into AGENT_TOOLSDIRECTORY=${process.env['AGENT_TOOLSDIRECTORY']}`);
- process.env['RUNNER_TOOL_CACHE'] = process.env['AGENT_TOOLSDIRECTORY'];
+ core.debug(`Python is expected to be installed into RUNNER_TOOL_CACHE=${process.env['RUNNER_TOOL_CACHE']}`);
try {
const version = core.getInput('python-version');
if (version) {
diff --git a/src/setup-python.ts b/src/setup-python.ts
index 0b1553b0..20bc8ffe 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -49,14 +49,16 @@ function resolveVersionInput(): string {
}
async function run() {
+ // According to the README windows binaries do not require to be installed
+ // in the specific location, but Mac and Linux do
if (!IS_WINDOWS && !process.env.AGENT_TOOLSDIRECTORY?.trim()) {
if (IS_LINUX) process.env['AGENT_TOOLSDIRECTORY'] = '/opt/hostedtoolcache';
else process.env['AGENT_TOOLSDIRECTORY'] = '/Users/runner/hostedtoolcache';
+ process.env['RUNNER_TOOL_CACHE'] = process.env['AGENT_TOOLSDIRECTORY'];
}
core.debug(
- `Python is expected to be installed into AGENT_TOOLSDIRECTORY=${process.env['AGENT_TOOLSDIRECTORY']}`
+ `Python is expected to be installed into RUNNER_TOOL_CACHE=${process.env['RUNNER_TOOL_CACHE']}`
);
- process.env['RUNNER_TOOL_CACHE'] = process.env['AGENT_TOOLSDIRECTORY'];
try {
const version = resolveVersionInput();
if (version) {
From 9c76df2a906d23390826e21a05ccb6e3abbbda34 Mon Sep 17 00:00:00 2001
From: Sergey Dolin
Date: Wed, 29 Jun 2022 11:24:02 +0200
Subject: [PATCH 08/77] Build after rebase
---
dist/setup/index.js | 142 +++-----------------------------------------
1 file changed, 8 insertions(+), 134 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 6d75cc20..8c554859 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -5225,139 +5225,10 @@ class ToolRunner extends events.EventEmitter {
return (this._endsWith(upperToolPath, '.CMD') ||
this._endsWith(upperToolPath, '.BAT'));
}
-<<<<<<< HEAD
_windowsQuoteCmdArg(arg) {
// for .exe, apply the normal quoting rules that libuv applies
if (!this._isCmdFile()) {
return this._uvQuoteCmdArg(arg);
-=======
-
- const sameDirectionIncreasing =
- (this.operator === '>=' || this.operator === '>') &&
- (comp.operator === '>=' || comp.operator === '>')
- const sameDirectionDecreasing =
- (this.operator === '<=' || this.operator === '<') &&
- (comp.operator === '<=' || comp.operator === '<')
- const sameSemVer = this.semver.version === comp.semver.version
- const differentDirectionsInclusive =
- (this.operator === '>=' || this.operator === '<=') &&
- (comp.operator === '>=' || comp.operator === '<=')
- const oppositeDirectionsLessThan =
- cmp(this.semver, '<', comp.semver, options) &&
- (this.operator === '>=' || this.operator === '>') &&
- (comp.operator === '<=' || comp.operator === '<')
- const oppositeDirectionsGreaterThan =
- cmp(this.semver, '>', comp.semver, options) &&
- (this.operator === '<=' || this.operator === '<') &&
- (comp.operator === '>=' || comp.operator === '>')
-
- return (
- sameDirectionIncreasing ||
- sameDirectionDecreasing ||
- (sameSemVer && differentDirectionsInclusive) ||
- oppositeDirectionsLessThan ||
- oppositeDirectionsGreaterThan
- )
- }
-}
-
-module.exports = Comparator
-
-const {re, t} = __webpack_require__(328)
-const cmp = __webpack_require__(752)
-const debug = __webpack_require__(548)
-const SemVer = __webpack_require__(206)
-const Range = __webpack_require__(124)
-
-
-/***/ }),
-/* 175 */
-/***/ (function(__unusedmodule, exports, __webpack_require__) {
-
-"use strict";
-
-var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
- if (k2 === undefined) k2 = k;
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
-}) : (function(o, m, k, k2) {
- if (k2 === undefined) k2 = k;
- o[k2] = m[k];
-}));
-var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
- Object.defineProperty(o, "default", { enumerable: true, value: v });
-}) : function(o, v) {
- o["default"] = v;
-});
-var __importStar = (this && this.__importStar) || function (mod) {
- if (mod && mod.__esModule) return mod;
- var result = {};
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
- __setModuleDefault(result, mod);
- return result;
-};
-var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
- return new (P || (P = Promise))(function (resolve, reject) {
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
-};
-Object.defineProperty(exports, "__esModule", { value: true });
-const core = __importStar(__webpack_require__(470));
-const finder = __importStar(__webpack_require__(927));
-const finderPyPy = __importStar(__webpack_require__(847));
-const path = __importStar(__webpack_require__(622));
-const os = __importStar(__webpack_require__(87));
-const cache_factory_1 = __webpack_require__(633);
-const utils_1 = __webpack_require__(163);
-function isPyPyVersion(versionSpec) {
- return versionSpec.startsWith('pypy-');
-}
-function cacheDependencies(cache, pythonVersion) {
- return __awaiter(this, void 0, void 0, function* () {
- const cacheDependencyPath = core.getInput('cache-dependency-path') || undefined;
- const cacheDistributor = cache_factory_1.getCacheDistributor(cache, pythonVersion, cacheDependencyPath);
- yield cacheDistributor.restoreCache();
- });
-}
-function run() {
- var _a;
- return __awaiter(this, void 0, void 0, function* () {
- // According to the README windows binaries do not require to be installed
- // in the specific location, but Mac and Linux do
- if (!utils_1.IS_WINDOWS && !((_a = process.env.AGENT_TOOLSDIRECTORY) === null || _a === void 0 ? void 0 : _a.trim())) {
- if (utils_1.IS_LINUX)
- process.env['AGENT_TOOLSDIRECTORY'] = '/opt/hostedtoolcache';
- else
- process.env['AGENT_TOOLSDIRECTORY'] = '/Users/runner/hostedtoolcache';
- process.env['RUNNER_TOOL_CACHE'] = process.env['AGENT_TOOLSDIRECTORY'];
- }
- core.debug(`Python is expected to be installed into RUNNER_TOOL_CACHE=${process.env['RUNNER_TOOL_CACHE']}`);
- try {
- const version = core.getInput('python-version');
- if (version) {
- let pythonVersion;
- const arch = core.getInput('architecture') || os.arch();
- if (isPyPyVersion(version)) {
- const installed = yield finderPyPy.findPyPyVersion(version, arch);
- pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`;
- core.info(`Successfully setup PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})`);
- }
- else {
- const installed = yield finder.useCpythonVersion(version, arch);
- pythonVersion = installed.version;
- core.info(`Successfully setup ${installed.impl} (${pythonVersion})`);
- }
- const cache = core.getInput('cache');
- if (cache && utils_1.isCacheFeatureAvailable()) {
- yield cacheDependencies(cache, pythonVersion);
- }
- }
- const matchersPath = path.join(__dirname, '../..', '.github');
- core.info(`##[add-matcher]${path.join(matchersPath, 'python.json')}`);
->>>>>>> 99015f8 (Use /opt/hostedtoolcache as default value AGENT_TOOLSDIRECTORY)
}
// otherwise apply quoting rules specific to the cmd.exe command line parser.
// the libuv rules are generic and are not designed specifically for cmd.exe
@@ -64693,13 +64564,16 @@ function resolveVersionInput() {
function run() {
var _a;
return __awaiter(this, void 0, void 0, function* () {
- if ((_a = process.env.AGENT_TOOLSDIRECTORY) === null || _a === void 0 ? void 0 : _a.trim()) {
- core.debug(`Python is expected to be installed into AGENT_TOOLSDIRECTORY=${process.env['AGENT_TOOLSDIRECTORY']}`);
+ // According to the README windows binaries do not require to be installed
+ // in the specific location, but Mac and Linux do
+ if (!utils_1.IS_WINDOWS && !((_a = process.env.AGENT_TOOLSDIRECTORY) === null || _a === void 0 ? void 0 : _a.trim())) {
+ if (utils_1.IS_LINUX)
+ process.env['AGENT_TOOLSDIRECTORY'] = '/opt/hostedtoolcache';
+ else
+ process.env['AGENT_TOOLSDIRECTORY'] = '/Users/runner/hostedtoolcache';
process.env['RUNNER_TOOL_CACHE'] = process.env['AGENT_TOOLSDIRECTORY'];
}
- else {
- core.debug(`Python is expected to be installed into RUNNER_TOOL_CACHE==${process.env['RUNNER_TOOL_CACHE']}`);
- }
+ core.debug(`Python is expected to be installed into RUNNER_TOOL_CACHE=${process.env['RUNNER_TOOL_CACHE']}`);
try {
const version = resolveVersionInput();
if (version) {
From 00a5248c77bed9280afb34f891aa24a152490ab5 Mon Sep 17 00:00:00 2001
From: Matthieu Darbois
Date: Wed, 29 Jun 2022 17:00:51 +0200
Subject: [PATCH 09/77] feature: add `update-environment` input (#411)
This option allows to specify if the action shall update environment variables (default) or not.
This allows to use the setup-python action in a composite action without side effect (except downloading/installing python if version is missing).
---
.github/workflows/test-pypy.yml | 26 +
.github/workflows/test-python.yml | 25 +
.licenses/npm/@actions/core.dep.yml | 2 +-
.../npm/@actions/http-client-1.0.8.dep.yml | 32 -
...ent-1.0.11.dep.yml => http-client.dep.yml} | 0
README.md | 20 +
__tests__/find-pypy.test.ts | 52 +-
__tests__/finder.test.ts | 59 +-
action.yml | 3 +
dist/cache-save/index.js | 1890 +++++++++++------
dist/setup/index.js | 1384 ++++++------
package-lock.json | 48 +-
package.json | 2 +-
src/find-pypy.ts | 13 +-
src/find-python.ts | 66 +-
src/setup-python.ts | 13 +-
16 files changed, 2083 insertions(+), 1552 deletions(-)
delete mode 100644 .licenses/npm/@actions/http-client-1.0.8.dep.yml
rename .licenses/npm/@actions/{http-client-1.0.11.dep.yml => http-client.dep.yml} (100%)
diff --git a/.github/workflows/test-pypy.yml b/.github/workflows/test-pypy.yml
index 5f23b213..e4a53bb2 100644
--- a/.github/workflows/test-pypy.yml
+++ b/.github/workflows/test-pypy.yml
@@ -65,3 +65,29 @@ jobs:
EXECUTABLE=${EXECUTABLE%%-*} # remove any -* suffixe
${EXECUTABLE} --version
shell: bash
+
+ setup-pypy-noenv:
+ name: Setup PyPy ${{ matrix.pypy }} ${{ matrix.os }} (noenv)
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-latest]
+ pypy: ['pypy2.7', 'pypy3.7', 'pypy3.8', 'pypy3.9-nightly']
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: setup-python ${{ matrix.pypy }}
+ id: setup-python
+ uses: ./
+ with:
+ python-version: ${{ matrix.pypy }}
+ update-environment: false
+
+ - name: PyPy and Python version
+ run: ${{ steps.setup-python.outputs.python-path }} --version
+
+ - name: Run simple code
+ run: ${{ steps.setup-python.outputs.python-path }} -c 'import math; print(math.factorial(5))'
diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml
index e0d9a47d..17709ec5 100644
--- a/.github/workflows/test-python.yml
+++ b/.github/workflows/test-python.yml
@@ -147,3 +147,28 @@ jobs:
- name: Run simple code
run: python -c 'import math; print(math.factorial(5))'
+
+ setup-versions-noenv:
+ name: Setup ${{ matrix.python }} ${{ matrix.os }} (noenv)
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-20.04]
+ python: ["3.7", "3.8", "3.9", "3.10"]
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: setup-python ${{ matrix.python }}
+ id: setup-python
+ uses: ./
+ with:
+ python-version: ${{ matrix.python }}
+ update-environment: false
+
+ - name: Python version
+ run: ${{ steps.setup-python.outputs.python-path }} --version
+
+ - name: Run simple code
+ run: ${{ steps.setup-python.outputs.python-path }} -c 'import math; print(math.factorial(5))'
diff --git a/.licenses/npm/@actions/core.dep.yml b/.licenses/npm/@actions/core.dep.yml
index b1152f59..6ef1a3d4 100644
--- a/.licenses/npm/@actions/core.dep.yml
+++ b/.licenses/npm/@actions/core.dep.yml
@@ -1,6 +1,6 @@
---
name: "@actions/core"
-version: 1.2.6
+version: 1.7.0
type: npm
summary: Actions core lib
homepage: https://github.com/actions/toolkit/tree/main/packages/core
diff --git a/.licenses/npm/@actions/http-client-1.0.8.dep.yml b/.licenses/npm/@actions/http-client-1.0.8.dep.yml
deleted file mode 100644
index d18a24ff..00000000
--- a/.licenses/npm/@actions/http-client-1.0.8.dep.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: "@actions/http-client"
-version: 1.0.8
-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: []
diff --git a/.licenses/npm/@actions/http-client-1.0.11.dep.yml b/.licenses/npm/@actions/http-client.dep.yml
similarity index 100%
rename from .licenses/npm/@actions/http-client-1.0.11.dep.yml
rename to .licenses/npm/@actions/http-client.dep.yml
diff --git a/README.md b/README.md
index d5968fdc..5adb2033 100644
--- a/README.md
+++ b/README.md
@@ -320,6 +320,26 @@ steps:
- run: pipenv install
```
+# Environment variables
+
+ The `update-environment` flag defaults to `true`.
+ With this setting, the action will add/update environment variables (e.g. `PATH`, `PKG_CONFIG_PATH`, `pythonLocation`) for `python` to just work out of the box.
+
+ If `update-environment` is set to `false`, the action will not add/update environment variables.
+ This can prove useful if you want the only side-effect to be to ensure python is installed and rely on the `python-path` output to run python.
+ Such a requirement on side-effect could be because you don't want your composite action messing with your user's workflows.
+
+ ```yaml
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-python@v4
+ id: cp310
+ with:
+ python-version: '3.10'
+ update-environment: false
+ - run: ${{ steps.cp310.outputs.python-path }} my_script.py
+ ```
+
# Using `setup-python` with a self hosted runner
Python distributions are only available for the same [environments](https://github.com/actions/virtual-environments#available-environments) that GitHub Actions hosted environments are available for. If you are using an unsupported version of Ubuntu such as `19.04` or another Linux distribution such as Fedora, `setup-python` will not work. If you have a supported self-hosted runner and you would like to use `setup-python`, there are a few extra things you need to make sure are set up so that new versions of Python can be downloaded and configured on your runner.
diff --git a/__tests__/find-pypy.test.ts b/__tests__/find-pypy.test.ts
index 8cb32509..04a27cf3 100644
--- a/__tests__/find-pypy.test.ts
+++ b/__tests__/find-pypy.test.ts
@@ -5,6 +5,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 semver from 'semver';
@@ -148,6 +149,8 @@ describe('findPyPyVersion', () => {
let spyWriteExactPyPyVersionFile: jest.SpyInstance;
let spyCacheDir: jest.SpyInstance;
let spyChmodSync: jest.SpyInstance;
+ let spyCoreAddPath: jest.SpyInstance;
+ let spyCoreExportVariable: jest.SpyInstance;
beforeEach(() => {
tcFind = jest.spyOn(tc, 'find');
@@ -201,6 +204,10 @@ describe('findPyPyVersion', () => {
spyExistsSync = jest.spyOn(fs, 'existsSync');
spyExistsSync.mockReturnValue(true);
+
+ spyCoreAddPath = jest.spyOn(core, 'addPath');
+
+ spyCoreExportVariable = jest.spyOn(core, 'exportVariable');
});
afterEach(() => {
@@ -211,22 +218,31 @@ describe('findPyPyVersion', () => {
it('found PyPy in toolcache', async () => {
await expect(
- finder.findPyPyVersion('pypy-3.6-v7.3.x', architecture)
+ finder.findPyPyVersion('pypy-3.6-v7.3.x', architecture, true)
).resolves.toEqual({
resolvedPythonVersion: '3.6.12',
resolvedPyPyVersion: '7.3.3'
});
+ 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.findPyPyVersion('pypy3.7-v7.3.x', architecture)
+ finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, true)
).rejects.toThrow();
});
it('throw on invalid input format pypy3.7-7.3.x', async () => {
await expect(
- finder.findPyPyVersion('pypy3.7-v7.3.x', architecture)
+ finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, true)
).rejects.toThrow();
});
@@ -238,16 +254,42 @@ describe('findPyPyVersion', () => {
spyChmodSync = jest.spyOn(fs, 'chmodSync');
spyChmodSync.mockImplementation(() => undefined);
await expect(
- finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture)
+ finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, true)
).resolves.toEqual({
resolvedPythonVersion: '3.7.9',
resolvedPyPyVersion: '7.3.3'
});
+ 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, '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)
+ ).resolves.toEqual({
+ resolvedPythonVersion: '3.7.9',
+ resolvedPyPyVersion: '7.3.3'
+ });
+ expect(spyCoreAddPath).not.toHaveBeenCalled();
+ expect(spyCoreExportVariable).not.toHaveBeenCalled();
});
it('throw if release is not found', async () => {
await expect(
- finder.findPyPyVersion('pypy-3.7-v7.5.x', architecture)
+ finder.findPyPyVersion('pypy-3.7-v7.5.x', architecture, true)
).rejects.toThrowError(
`PyPy version 3.7 (v7.5.x) with arch ${architecture} not found`
);
diff --git a/__tests__/finder.test.ts b/__tests__/finder.test.ts
index d4805696..cf07a234 100644
--- a/__tests__/finder.test.ts
+++ b/__tests__/finder.test.ts
@@ -19,15 +19,26 @@ process.env['RUNNER_TOOL_CACHE'] = toolDir;
process.env['RUNNER_TEMP'] = tempDir;
import * as tc from '@actions/tool-cache';
+import * as core from '@actions/core';
import * as finder from '../src/find-python';
import * as installer from '../src/install-python';
const manifestData = require('./data/versions-manifest.json');
describe('Finder tests', () => {
+ let spyCoreAddPath: jest.SpyInstance;
+ let spyCoreExportVariable: jest.SpyInstance;
+
+ beforeEach(() => {
+ spyCoreAddPath = jest.spyOn(core, 'addPath');
+
+ spyCoreExportVariable = jest.spyOn(core, 'exportVariable');
+ });
+
afterEach(() => {
jest.resetAllMocks();
jest.clearAllMocks();
+ jest.restoreAllMocks();
});
it('Finds Python if it is installed', async () => {
@@ -35,7 +46,27 @@ 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');
+ await finder.useCpythonVersion('3.x', 'x64', true);
+ expect(spyCoreAddPath).toHaveBeenCalled();
+ expect(spyCoreExportVariable).toHaveBeenCalledWith(
+ 'pythonLocation',
+ expect.anything()
+ );
+ expect(spyCoreExportVariable).toHaveBeenCalledWith(
+ 'PKG_CONFIG_PATH',
+ expect.anything()
+ );
+ });
+
+ it('Finds Python if it is installed without environment update', async () => {
+ 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', false);
+ expect(spyCoreAddPath).not.toHaveBeenCalled();
+ expect(spyCoreExportVariable).not.toHaveBeenCalled();
+ expect(spyCoreExportVariable).not.toHaveBeenCalled();
});
it('Finds stable Python version if it is not installed, but exists in the manifest', async () => {
@@ -52,7 +83,16 @@ 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');
+ await finder.useCpythonVersion('1.2.3', 'x64', true);
+ expect(spyCoreAddPath).toHaveBeenCalled();
+ expect(spyCoreExportVariable).toHaveBeenCalledWith(
+ 'pythonLocation',
+ expect.anything()
+ );
+ expect(spyCoreExportVariable).toHaveBeenCalledWith(
+ 'PKG_CONFIG_PATH',
+ expect.anything()
+ );
});
it('Finds pre-release Python version in the manifest', async () => {
@@ -74,17 +114,28 @@ 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');
+ await finder.useCpythonVersion('1.2.3-beta.2', 'x64', true);
+ expect(spyCoreAddPath).toHaveBeenCalled();
+ expect(spyCoreExportVariable).toHaveBeenCalledWith(
+ 'pythonLocation',
+ expect.anything()
+ );
+ expect(spyCoreExportVariable).toHaveBeenCalledWith(
+ 'PKG_CONFIG_PATH',
+ expect.anything()
+ );
});
it('Errors if Python is not installed', async () => {
// 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');
+ await finder.useCpythonVersion('3.300000', 'x64', true);
} catch {
thrown = true;
}
expect(thrown).toBeTruthy();
+ expect(spyCoreAddPath).not.toHaveBeenCalled();
+ expect(spyCoreExportVariable).not.toHaveBeenCalled();
});
});
diff --git a/action.yml b/action.yml
index 27474e2a..de2a4feb 100644
--- a/action.yml
+++ b/action.yml
@@ -17,6 +17,9 @@ inputs:
default: ${{ github.token }}
cache-dependency-path:
description: 'Used to specify the path to dependency files. Supports wildcards or a list of file names for caching multiple dependencies.'
+ update-environment:
+ description: 'Set this option if you want the action to update environment variables.'
+ default: true
outputs:
python-version:
description: "The installed python version. Useful when given a version range as input."
diff --git a/dist/cache-save/index.js b/dist/cache-save/index.js
index 35cedd90..7c0104e2 100644
--- a/dist/cache-save/index.js
+++ b/dist/cache-save/index.js
@@ -214,8 +214,8 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(7320);
-const auth_1 = __nccwpck_require__(7093);
+const http_client_1 = __nccwpck_require__(9925);
+const auth_1 = __nccwpck_require__(3702);
const crypto = __importStar(__nccwpck_require__(6113));
const fs = __importStar(__nccwpck_require__(7147));
const url_1 = __nccwpck_require__(7310);
@@ -647,7 +647,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(7320);
+const http_client_1 = __nccwpck_require__(9925);
const storage_blob_1 = __nccwpck_require__(4100);
const buffer = __importStar(__nccwpck_require__(4300));
const fs = __importStar(__nccwpck_require__(7147));
@@ -885,7 +885,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(7320);
+const http_client_1 = __nccwpck_require__(9925);
const constants_1 = __nccwpck_require__(8840);
function isSuccessStatusCode(statusCode) {
if (!statusCode) {
@@ -2290,682 +2290,6 @@ class SearchState {
exports.SearchState = SearchState;
//# sourceMappingURL=internal-search-state.js.map
-/***/ }),
-
-/***/ 7093:
-/***/ ((__unused_webpack_module, exports) => {
-
-"use strict";
-
-Object.defineProperty(exports, "__esModule", ({ value: true }));
-class BasicCredentialHandler {
- constructor(username, password) {
- this.username = username;
- this.password = password;
- }
- prepareRequest(options) {
- options.headers['Authorization'] =
- 'Basic ' +
- Buffer.from(this.username + ':' + this.password).toString('base64');
- }
- // This handler cannot handle 401
- canHandleAuthentication(response) {
- return false;
- }
- handleAuthentication(httpClient, requestInfo, objs) {
- return null;
- }
-}
-exports.BasicCredentialHandler = BasicCredentialHandler;
-class BearerCredentialHandler {
- constructor(token) {
- this.token = token;
- }
- // currently implements pre-authorization
- // TODO: support preAuth = false where it hooks on 401
- prepareRequest(options) {
- options.headers['Authorization'] = 'Bearer ' + this.token;
- }
- // This handler cannot handle 401
- canHandleAuthentication(response) {
- return false;
- }
- handleAuthentication(httpClient, requestInfo, objs) {
- return null;
- }
-}
-exports.BearerCredentialHandler = BearerCredentialHandler;
-class PersonalAccessTokenCredentialHandler {
- constructor(token) {
- this.token = token;
- }
- // currently implements pre-authorization
- // TODO: support preAuth = false where it hooks on 401
- prepareRequest(options) {
- options.headers['Authorization'] =
- 'Basic ' + Buffer.from('PAT:' + this.token).toString('base64');
- }
- // This handler cannot handle 401
- canHandleAuthentication(response) {
- return false;
- }
- handleAuthentication(httpClient, requestInfo, objs) {
- return null;
- }
-}
-exports.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHandler;
-
-
-/***/ }),
-
-/***/ 7320:
-/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
-
-"use strict";
-
-Object.defineProperty(exports, "__esModule", ({ value: true }));
-const http = __nccwpck_require__(3685);
-const https = __nccwpck_require__(5687);
-const pm = __nccwpck_require__(7326);
-let tunnel;
-var HttpCodes;
-(function (HttpCodes) {
- HttpCodes[HttpCodes["OK"] = 200] = "OK";
- HttpCodes[HttpCodes["MultipleChoices"] = 300] = "MultipleChoices";
- HttpCodes[HttpCodes["MovedPermanently"] = 301] = "MovedPermanently";
- HttpCodes[HttpCodes["ResourceMoved"] = 302] = "ResourceMoved";
- HttpCodes[HttpCodes["SeeOther"] = 303] = "SeeOther";
- HttpCodes[HttpCodes["NotModified"] = 304] = "NotModified";
- HttpCodes[HttpCodes["UseProxy"] = 305] = "UseProxy";
- HttpCodes[HttpCodes["SwitchProxy"] = 306] = "SwitchProxy";
- HttpCodes[HttpCodes["TemporaryRedirect"] = 307] = "TemporaryRedirect";
- HttpCodes[HttpCodes["PermanentRedirect"] = 308] = "PermanentRedirect";
- HttpCodes[HttpCodes["BadRequest"] = 400] = "BadRequest";
- HttpCodes[HttpCodes["Unauthorized"] = 401] = "Unauthorized";
- HttpCodes[HttpCodes["PaymentRequired"] = 402] = "PaymentRequired";
- HttpCodes[HttpCodes["Forbidden"] = 403] = "Forbidden";
- HttpCodes[HttpCodes["NotFound"] = 404] = "NotFound";
- HttpCodes[HttpCodes["MethodNotAllowed"] = 405] = "MethodNotAllowed";
- HttpCodes[HttpCodes["NotAcceptable"] = 406] = "NotAcceptable";
- HttpCodes[HttpCodes["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
- HttpCodes[HttpCodes["RequestTimeout"] = 408] = "RequestTimeout";
- HttpCodes[HttpCodes["Conflict"] = 409] = "Conflict";
- HttpCodes[HttpCodes["Gone"] = 410] = "Gone";
- HttpCodes[HttpCodes["TooManyRequests"] = 429] = "TooManyRequests";
- HttpCodes[HttpCodes["InternalServerError"] = 500] = "InternalServerError";
- HttpCodes[HttpCodes["NotImplemented"] = 501] = "NotImplemented";
- HttpCodes[HttpCodes["BadGateway"] = 502] = "BadGateway";
- HttpCodes[HttpCodes["ServiceUnavailable"] = 503] = "ServiceUnavailable";
- HttpCodes[HttpCodes["GatewayTimeout"] = 504] = "GatewayTimeout";
-})(HttpCodes = exports.HttpCodes || (exports.HttpCodes = {}));
-var Headers;
-(function (Headers) {
- Headers["Accept"] = "accept";
- Headers["ContentType"] = "content-type";
-})(Headers = exports.Headers || (exports.Headers = {}));
-var MediaTypes;
-(function (MediaTypes) {
- MediaTypes["ApplicationJson"] = "application/json";
-})(MediaTypes = exports.MediaTypes || (exports.MediaTypes = {}));
-/**
- * Returns the proxy URL, depending upon the supplied url and proxy environment variables.
- * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
- */
-function getProxyUrl(serverUrl) {
- let proxyUrl = pm.getProxyUrl(new URL(serverUrl));
- return proxyUrl ? proxyUrl.href : '';
-}
-exports.getProxyUrl = getProxyUrl;
-const HttpRedirectCodes = [
- HttpCodes.MovedPermanently,
- HttpCodes.ResourceMoved,
- HttpCodes.SeeOther,
- HttpCodes.TemporaryRedirect,
- HttpCodes.PermanentRedirect
-];
-const HttpResponseRetryCodes = [
- HttpCodes.BadGateway,
- HttpCodes.ServiceUnavailable,
- HttpCodes.GatewayTimeout
-];
-const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD'];
-const ExponentialBackoffCeiling = 10;
-const ExponentialBackoffTimeSlice = 5;
-class HttpClientError extends Error {
- constructor(message, statusCode) {
- super(message);
- this.name = 'HttpClientError';
- this.statusCode = statusCode;
- Object.setPrototypeOf(this, HttpClientError.prototype);
- }
-}
-exports.HttpClientError = HttpClientError;
-class HttpClientResponse {
- constructor(message) {
- this.message = message;
- }
- readBody() {
- return new Promise(async (resolve, reject) => {
- let output = Buffer.alloc(0);
- this.message.on('data', (chunk) => {
- output = Buffer.concat([output, chunk]);
- });
- this.message.on('end', () => {
- resolve(output.toString());
- });
- });
- }
-}
-exports.HttpClientResponse = HttpClientResponse;
-function isHttps(requestUrl) {
- let parsedUrl = new URL(requestUrl);
- return parsedUrl.protocol === 'https:';
-}
-exports.isHttps = isHttps;
-class HttpClient {
- constructor(userAgent, handlers, requestOptions) {
- this._ignoreSslError = false;
- this._allowRedirects = true;
- this._allowRedirectDowngrade = false;
- this._maxRedirects = 50;
- this._allowRetries = false;
- this._maxRetries = 1;
- this._keepAlive = false;
- this._disposed = false;
- this.userAgent = userAgent;
- this.handlers = handlers || [];
- this.requestOptions = requestOptions;
- if (requestOptions) {
- if (requestOptions.ignoreSslError != null) {
- this._ignoreSslError = requestOptions.ignoreSslError;
- }
- this._socketTimeout = requestOptions.socketTimeout;
- if (requestOptions.allowRedirects != null) {
- this._allowRedirects = requestOptions.allowRedirects;
- }
- if (requestOptions.allowRedirectDowngrade != null) {
- this._allowRedirectDowngrade = requestOptions.allowRedirectDowngrade;
- }
- if (requestOptions.maxRedirects != null) {
- this._maxRedirects = Math.max(requestOptions.maxRedirects, 0);
- }
- if (requestOptions.keepAlive != null) {
- this._keepAlive = requestOptions.keepAlive;
- }
- if (requestOptions.allowRetries != null) {
- this._allowRetries = requestOptions.allowRetries;
- }
- if (requestOptions.maxRetries != null) {
- this._maxRetries = requestOptions.maxRetries;
- }
- }
- }
- options(requestUrl, additionalHeaders) {
- return this.request('OPTIONS', requestUrl, null, additionalHeaders || {});
- }
- get(requestUrl, additionalHeaders) {
- return this.request('GET', requestUrl, null, additionalHeaders || {});
- }
- del(requestUrl, additionalHeaders) {
- return this.request('DELETE', requestUrl, null, additionalHeaders || {});
- }
- post(requestUrl, data, additionalHeaders) {
- return this.request('POST', requestUrl, data, additionalHeaders || {});
- }
- patch(requestUrl, data, additionalHeaders) {
- return this.request('PATCH', requestUrl, data, additionalHeaders || {});
- }
- put(requestUrl, data, additionalHeaders) {
- return this.request('PUT', requestUrl, data, additionalHeaders || {});
- }
- head(requestUrl, additionalHeaders) {
- return this.request('HEAD', requestUrl, null, additionalHeaders || {});
- }
- sendStream(verb, requestUrl, stream, additionalHeaders) {
- return this.request(verb, requestUrl, stream, additionalHeaders);
- }
- /**
- * Gets a typed object from an endpoint
- * Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise
- */
- async getJson(requestUrl, additionalHeaders = {}) {
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- let res = await this.get(requestUrl, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
- }
- async postJson(requestUrl, obj, additionalHeaders = {}) {
- let data = JSON.stringify(obj, null, 2);
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
- let res = await this.post(requestUrl, data, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
- }
- async putJson(requestUrl, obj, additionalHeaders = {}) {
- let data = JSON.stringify(obj, null, 2);
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
- let res = await this.put(requestUrl, data, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
- }
- async patchJson(requestUrl, obj, additionalHeaders = {}) {
- let data = JSON.stringify(obj, null, 2);
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
- let res = await this.patch(requestUrl, data, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
- }
- /**
- * Makes a raw http request.
- * All other methods such as get, post, patch, and request ultimately call this.
- * Prefer get, del, post and patch
- */
- async request(verb, requestUrl, data, headers) {
- if (this._disposed) {
- throw new Error('Client has already been disposed.');
- }
- let parsedUrl = new URL(requestUrl);
- let info = this._prepareRequest(verb, parsedUrl, headers);
- // Only perform retries on reads since writes may not be idempotent.
- let maxTries = this._allowRetries && RetryableHttpVerbs.indexOf(verb) != -1
- ? this._maxRetries + 1
- : 1;
- let numTries = 0;
- let response;
- while (numTries < maxTries) {
- response = await this.requestRaw(info, data);
- // Check if it's an authentication challenge
- if (response &&
- response.message &&
- response.message.statusCode === HttpCodes.Unauthorized) {
- let authenticationHandler;
- for (let i = 0; i < this.handlers.length; i++) {
- if (this.handlers[i].canHandleAuthentication(response)) {
- authenticationHandler = this.handlers[i];
- break;
- }
- }
- if (authenticationHandler) {
- return authenticationHandler.handleAuthentication(this, info, data);
- }
- else {
- // We have received an unauthorized response but have no handlers to handle it.
- // Let the response return to the caller.
- return response;
- }
- }
- let redirectsRemaining = this._maxRedirects;
- while (HttpRedirectCodes.indexOf(response.message.statusCode) != -1 &&
- this._allowRedirects &&
- redirectsRemaining > 0) {
- const redirectUrl = response.message.headers['location'];
- if (!redirectUrl) {
- // if there's no location to redirect to, we won't
- break;
- }
- let parsedRedirectUrl = new URL(redirectUrl);
- if (parsedUrl.protocol == 'https:' &&
- parsedUrl.protocol != parsedRedirectUrl.protocol &&
- !this._allowRedirectDowngrade) {
- throw new Error('Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.');
- }
- // we need to finish reading the response before reassigning response
- // which will leak the open socket.
- await response.readBody();
- // strip authorization header if redirected to a different hostname
- if (parsedRedirectUrl.hostname !== parsedUrl.hostname) {
- for (let header in headers) {
- // header names are case insensitive
- if (header.toLowerCase() === 'authorization') {
- delete headers[header];
- }
- }
- }
- // let's make the request with the new redirectUrl
- info = this._prepareRequest(verb, parsedRedirectUrl, headers);
- response = await this.requestRaw(info, data);
- redirectsRemaining--;
- }
- if (HttpResponseRetryCodes.indexOf(response.message.statusCode) == -1) {
- // If not a retry code, return immediately instead of retrying
- return response;
- }
- numTries += 1;
- if (numTries < maxTries) {
- await response.readBody();
- await this._performExponentialBackoff(numTries);
- }
- }
- return response;
- }
- /**
- * Needs to be called if keepAlive is set to true in request options.
- */
- dispose() {
- if (this._agent) {
- this._agent.destroy();
- }
- this._disposed = true;
- }
- /**
- * Raw request.
- * @param info
- * @param data
- */
- requestRaw(info, data) {
- return new Promise((resolve, reject) => {
- let callbackForResult = function (err, res) {
- if (err) {
- reject(err);
- }
- resolve(res);
- };
- this.requestRawWithCallback(info, data, callbackForResult);
- });
- }
- /**
- * Raw request with callback.
- * @param info
- * @param data
- * @param onResult
- */
- requestRawWithCallback(info, data, onResult) {
- let socket;
- if (typeof data === 'string') {
- info.options.headers['Content-Length'] = Buffer.byteLength(data, 'utf8');
- }
- let callbackCalled = false;
- let handleResult = (err, res) => {
- if (!callbackCalled) {
- callbackCalled = true;
- onResult(err, res);
- }
- };
- let req = info.httpModule.request(info.options, (msg) => {
- let res = new HttpClientResponse(msg);
- handleResult(null, res);
- });
- req.on('socket', sock => {
- socket = sock;
- });
- // If we ever get disconnected, we want the socket to timeout eventually
- req.setTimeout(this._socketTimeout || 3 * 60000, () => {
- if (socket) {
- socket.end();
- }
- handleResult(new Error('Request timeout: ' + info.options.path), null);
- });
- req.on('error', function (err) {
- // err has statusCode property
- // res should have headers
- handleResult(err, null);
- });
- if (data && typeof data === 'string') {
- req.write(data, 'utf8');
- }
- if (data && typeof data !== 'string') {
- data.on('close', function () {
- req.end();
- });
- data.pipe(req);
- }
- else {
- req.end();
- }
- }
- /**
- * Gets an http agent. This function is useful when you need an http agent that handles
- * routing through a proxy server - depending upon the url and proxy environment variables.
- * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
- */
- getAgent(serverUrl) {
- let parsedUrl = new URL(serverUrl);
- return this._getAgent(parsedUrl);
- }
- _prepareRequest(method, requestUrl, headers) {
- const info = {};
- info.parsedUrl = requestUrl;
- const usingSsl = info.parsedUrl.protocol === 'https:';
- info.httpModule = usingSsl ? https : http;
- const defaultPort = usingSsl ? 443 : 80;
- info.options = {};
- info.options.host = info.parsedUrl.hostname;
- info.options.port = info.parsedUrl.port
- ? parseInt(info.parsedUrl.port)
- : defaultPort;
- info.options.path =
- (info.parsedUrl.pathname || '') + (info.parsedUrl.search || '');
- info.options.method = method;
- info.options.headers = this._mergeHeaders(headers);
- if (this.userAgent != null) {
- info.options.headers['user-agent'] = this.userAgent;
- }
- info.options.agent = this._getAgent(info.parsedUrl);
- // gives handlers an opportunity to participate
- if (this.handlers) {
- this.handlers.forEach(handler => {
- handler.prepareRequest(info.options);
- });
- }
- return info;
- }
- _mergeHeaders(headers) {
- const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
- if (this.requestOptions && this.requestOptions.headers) {
- return Object.assign({}, lowercaseKeys(this.requestOptions.headers), lowercaseKeys(headers));
- }
- return lowercaseKeys(headers || {});
- }
- _getExistingOrDefaultHeader(additionalHeaders, header, _default) {
- const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
- let clientHeader;
- if (this.requestOptions && this.requestOptions.headers) {
- clientHeader = lowercaseKeys(this.requestOptions.headers)[header];
- }
- return additionalHeaders[header] || clientHeader || _default;
- }
- _getAgent(parsedUrl) {
- let agent;
- let proxyUrl = pm.getProxyUrl(parsedUrl);
- let useProxy = proxyUrl && proxyUrl.hostname;
- if (this._keepAlive && useProxy) {
- agent = this._proxyAgent;
- }
- if (this._keepAlive && !useProxy) {
- agent = this._agent;
- }
- // if agent is already assigned use that agent.
- if (!!agent) {
- return agent;
- }
- const usingSsl = parsedUrl.protocol === 'https:';
- let maxSockets = 100;
- if (!!this.requestOptions) {
- maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets;
- }
- if (useProxy) {
- // If using proxy, need tunnel
- if (!tunnel) {
- tunnel = __nccwpck_require__(4294);
- }
- const agentOptions = {
- maxSockets: maxSockets,
- keepAlive: this._keepAlive,
- proxy: {
- ...((proxyUrl.username || proxyUrl.password) && {
- proxyAuth: `${proxyUrl.username}:${proxyUrl.password}`
- }),
- host: proxyUrl.hostname,
- port: proxyUrl.port
- }
- };
- let tunnelAgent;
- const overHttps = proxyUrl.protocol === 'https:';
- if (usingSsl) {
- tunnelAgent = overHttps ? tunnel.httpsOverHttps : tunnel.httpsOverHttp;
- }
- else {
- tunnelAgent = overHttps ? tunnel.httpOverHttps : tunnel.httpOverHttp;
- }
- agent = tunnelAgent(agentOptions);
- this._proxyAgent = agent;
- }
- // if reusing agent across request and tunneling agent isn't assigned create a new agent
- if (this._keepAlive && !agent) {
- const options = { keepAlive: this._keepAlive, maxSockets: maxSockets };
- agent = usingSsl ? new https.Agent(options) : new http.Agent(options);
- this._agent = agent;
- }
- // if not using private agent and tunnel agent isn't setup then use global agent
- if (!agent) {
- agent = usingSsl ? https.globalAgent : http.globalAgent;
- }
- if (usingSsl && this._ignoreSslError) {
- // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process
- // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options
- // we have to cast it to any and change it directly
- agent.options = Object.assign(agent.options || {}, {
- rejectUnauthorized: false
- });
- }
- return agent;
- }
- _performExponentialBackoff(retryNumber) {
- retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber);
- const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber);
- return new Promise(resolve => setTimeout(() => resolve(), ms));
- }
- static dateTimeDeserializer(key, value) {
- if (typeof value === 'string') {
- let a = new Date(value);
- if (!isNaN(a.valueOf())) {
- return a;
- }
- }
- return value;
- }
- async _processResponse(res, options) {
- return new Promise(async (resolve, reject) => {
- const statusCode = res.message.statusCode;
- const response = {
- statusCode: statusCode,
- result: null,
- headers: {}
- };
- // not found leads to null obj returned
- if (statusCode == HttpCodes.NotFound) {
- resolve(response);
- }
- let obj;
- let contents;
- // get the result from the body
- try {
- contents = await res.readBody();
- if (contents && contents.length > 0) {
- if (options && options.deserializeDates) {
- obj = JSON.parse(contents, HttpClient.dateTimeDeserializer);
- }
- else {
- obj = JSON.parse(contents);
- }
- response.result = obj;
- }
- response.headers = res.message.headers;
- }
- catch (err) {
- // Invalid resource (contents not json); leaving result obj null
- }
- // note that 3xx redirects are handled by the http layer.
- if (statusCode > 299) {
- let msg;
- // if exception/error in body, attempt to get better error
- if (obj && obj.message) {
- msg = obj.message;
- }
- else if (contents && contents.length > 0) {
- // it may be the case that the exception is in the body message as string
- msg = contents;
- }
- else {
- msg = 'Failed request: (' + statusCode + ')';
- }
- let err = new HttpClientError(msg, statusCode);
- err.result = response.result;
- reject(err);
- }
- else {
- resolve(response);
- }
- });
- }
-}
-exports.HttpClient = HttpClient;
-
-
-/***/ }),
-
-/***/ 7326:
-/***/ ((__unused_webpack_module, exports) => {
-
-"use strict";
-
-Object.defineProperty(exports, "__esModule", ({ value: true }));
-function getProxyUrl(reqUrl) {
- let usingSsl = reqUrl.protocol === 'https:';
- let proxyUrl;
- if (checkBypass(reqUrl)) {
- return proxyUrl;
- }
- let proxyVar;
- if (usingSsl) {
- proxyVar = process.env['https_proxy'] || process.env['HTTPS_PROXY'];
- }
- else {
- proxyVar = process.env['http_proxy'] || process.env['HTTP_PROXY'];
- }
- if (proxyVar) {
- proxyUrl = new URL(proxyVar);
- }
- return proxyUrl;
-}
-exports.getProxyUrl = getProxyUrl;
-function checkBypass(reqUrl) {
- if (!reqUrl.hostname) {
- return false;
- }
- let noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || '';
- if (!noProxy) {
- return false;
- }
- // Determine the request port
- let reqPort;
- if (reqUrl.port) {
- reqPort = Number(reqUrl.port);
- }
- else if (reqUrl.protocol === 'http:') {
- reqPort = 80;
- }
- else if (reqUrl.protocol === 'https:') {
- reqPort = 443;
- }
- // Format the request hostname and hostname with port
- let upperReqHosts = [reqUrl.hostname.toUpperCase()];
- if (typeof reqPort === 'number') {
- upperReqHosts.push(`${upperReqHosts[0]}:${reqPort}`);
- }
- // Compare request host against noproxy
- for (let upperNoProxyItem of noProxy
- .split(',')
- .map(x => x.trim().toUpperCase())
- .filter(x => x)) {
- if (upperReqHosts.some(x => x === upperNoProxyItem)) {
- return true;
- }
- }
- return false;
-}
-exports.checkBypass = checkBypass;
-
-
/***/ }),
/***/ 3771:
@@ -4576,14 +3900,27 @@ function coerce (version, options) {
"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
- if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
- result["default"] = mod;
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.issue = exports.issueCommand = void 0;
const os = __importStar(__nccwpck_require__(2037));
const utils_1 = __nccwpck_require__(5278);
/**
@@ -4662,6 +3999,25 @@ function escapeProperty(s) {
"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
@@ -4671,19 +4027,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
-var __importStar = (this && this.__importStar) || function (mod) {
- if (mod && mod.__esModule) return mod;
- var result = {};
- if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
- result["default"] = mod;
- return result;
-};
Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.getIDToken = exports.getState = exports.saveState = exports.group = exports.endGroup = exports.startGroup = exports.info = exports.notice = exports.warning = exports.error = exports.debug = exports.isDebug = exports.setFailed = exports.setCommandEcho = exports.setOutput = exports.getBooleanInput = exports.getMultilineInput = exports.getInput = exports.addPath = exports.setSecret = exports.exportVariable = exports.ExitCode = void 0;
const command_1 = __nccwpck_require__(7351);
const file_command_1 = __nccwpck_require__(717);
const utils_1 = __nccwpck_require__(5278);
const os = __importStar(__nccwpck_require__(2037));
const path = __importStar(__nccwpck_require__(1017));
+const oidc_utils_1 = __nccwpck_require__(8041);
/**
* The code to exit an action
*/
@@ -4745,7 +4096,9 @@ function addPath(inputPath) {
}
exports.addPath = addPath;
/**
- * Gets the value of an input. The value is also trimmed.
+ * Gets the value of an input.
+ * Unless trimWhitespace is set to false in InputOptions, the value is also trimmed.
+ * Returns an empty string if the value is not defined.
*
* @param name name of the input to get
* @param options optional. See InputOptions.
@@ -4756,9 +4109,49 @@ function getInput(name, options) {
if (options && options.required && !val) {
throw new Error(`Input required and not supplied: ${name}`);
}
+ if (options && options.trimWhitespace === false) {
+ return val;
+ }
return val.trim();
}
exports.getInput = getInput;
+/**
+ * Gets the values of an multiline input. Each value is also trimmed.
+ *
+ * @param name name of the input to get
+ * @param options optional. See InputOptions.
+ * @returns string[]
+ *
+ */
+function getMultilineInput(name, options) {
+ const inputs = getInput(name, options)
+ .split('\n')
+ .filter(x => x !== '');
+ return inputs;
+}
+exports.getMultilineInput = getMultilineInput;
+/**
+ * Gets the input value of the boolean type in the YAML 1.2 "core schema" specification.
+ * Support boolean input list: `true | True | TRUE | false | False | FALSE` .
+ * The return value is also in boolean type.
+ * ref: https://yaml.org/spec/1.2/spec.html#id2804923
+ *
+ * @param name name of the input to get
+ * @param options optional. See InputOptions.
+ * @returns boolean
+ */
+function getBooleanInput(name, options) {
+ const trueValue = ['true', 'True', 'TRUE'];
+ const falseValue = ['false', 'False', 'FALSE'];
+ const val = getInput(name, options);
+ if (trueValue.includes(val))
+ return true;
+ if (falseValue.includes(val))
+ return false;
+ throw new TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${name}\n` +
+ `Support boolean input list: \`true | True | TRUE | false | False | FALSE\``);
+}
+exports.getBooleanInput = getBooleanInput;
/**
* Sets the value of an output.
*
@@ -4767,6 +4160,7 @@ exports.getInput = getInput;
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function setOutput(name, value) {
+ process.stdout.write(os.EOL);
command_1.issueCommand('set-output', { name }, value);
}
exports.setOutput = setOutput;
@@ -4813,19 +4207,30 @@ exports.debug = debug;
/**
* Adds an error issue
* @param message error issue message. Errors will be converted to string via toString()
+ * @param properties optional properties to add to the annotation.
*/
-function error(message) {
- command_1.issue('error', message instanceof Error ? message.toString() : message);
+function error(message, properties = {}) {
+ command_1.issueCommand('error', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message);
}
exports.error = error;
/**
- * Adds an warning issue
+ * Adds a warning issue
* @param message warning issue message. Errors will be converted to string via toString()
+ * @param properties optional properties to add to the annotation.
*/
-function warning(message) {
- command_1.issue('warning', message instanceof Error ? message.toString() : message);
+function warning(message, properties = {}) {
+ command_1.issueCommand('warning', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message);
}
exports.warning = warning;
+/**
+ * Adds a notice issue
+ * @param message notice issue message. Errors will be converted to string via toString()
+ * @param properties optional properties to add to the annotation.
+ */
+function notice(message, properties = {}) {
+ command_1.issueCommand('notice', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message);
+}
+exports.notice = notice;
/**
* Writes info to log with console.log.
* @param message info message
@@ -4898,6 +4303,17 @@ function getState(name) {
return process.env[`STATE_${name}`] || '';
}
exports.getState = getState;
+function getIDToken(aud) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return yield oidc_utils_1.OidcClient.getIDToken(aud);
+ });
+}
+exports.getIDToken = getIDToken;
+/**
+ * Markdown summary exports
+ */
+var markdown_summary_1 = __nccwpck_require__(8042);
+Object.defineProperty(exports, "markdownSummary", ({ enumerable: true, get: function () { return markdown_summary_1.markdownSummary; } }));
//# sourceMappingURL=core.js.map
/***/ }),
@@ -4908,14 +4324,27 @@ exports.getState = getState;
"use strict";
// For internal use, subject to change.
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
- if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
- result["default"] = mod;
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.issueCommand = void 0;
// We use any as a valid input type
/* eslint-disable @typescript-eslint/no-explicit-any */
const fs = __importStar(__nccwpck_require__(7147));
@@ -4938,6 +4367,376 @@ exports.issueCommand = issueCommand;
/***/ }),
+/***/ 8042:
+/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
+
+"use strict";
+
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.markdownSummary = exports.SUMMARY_DOCS_URL = exports.SUMMARY_ENV_VAR = void 0;
+const os_1 = __nccwpck_require__(2037);
+const fs_1 = __nccwpck_require__(7147);
+const { access, appendFile, writeFile } = fs_1.promises;
+exports.SUMMARY_ENV_VAR = 'GITHUB_STEP_SUMMARY';
+exports.SUMMARY_DOCS_URL = 'https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary';
+class MarkdownSummary {
+ constructor() {
+ this._buffer = '';
+ }
+ /**
+ * Finds the summary file path from the environment, rejects if env var is not found or file does not exist
+ * Also checks r/w permissions.
+ *
+ * @returns step summary file path
+ */
+ filePath() {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (this._filePath) {
+ return this._filePath;
+ }
+ const pathFromEnv = process.env[exports.SUMMARY_ENV_VAR];
+ if (!pathFromEnv) {
+ throw new Error(`Unable to find environment variable for $${exports.SUMMARY_ENV_VAR}. Check if your runtime environment supports markdown summaries.`);
+ }
+ try {
+ yield access(pathFromEnv, fs_1.constants.R_OK | fs_1.constants.W_OK);
+ }
+ catch (_a) {
+ throw new Error(`Unable to access summary file: '${pathFromEnv}'. Check if the file has correct read/write permissions.`);
+ }
+ this._filePath = pathFromEnv;
+ return this._filePath;
+ });
+ }
+ /**
+ * Wraps content in an HTML tag, adding any HTML attributes
+ *
+ * @param {string} tag HTML tag to wrap
+ * @param {string | null} content content within the tag
+ * @param {[attribute: string]: string} attrs key-value list of HTML attributes to add
+ *
+ * @returns {string} content wrapped in HTML element
+ */
+ wrap(tag, content, attrs = {}) {
+ const htmlAttrs = Object.entries(attrs)
+ .map(([key, value]) => ` ${key}="${value}"`)
+ .join('');
+ if (!content) {
+ return `<${tag}${htmlAttrs}>`;
+ }
+ return `<${tag}${htmlAttrs}>${content}${tag}>`;
+ }
+ /**
+ * Writes text in the buffer to the summary buffer file and empties buffer. Will append by default.
+ *
+ * @param {SummaryWriteOptions} [options] (optional) options for write operation
+ *
+ * @returns {Promise} markdown summary instance
+ */
+ write(options) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const overwrite = !!(options === null || options === void 0 ? void 0 : options.overwrite);
+ const filePath = yield this.filePath();
+ const writeFunc = overwrite ? writeFile : appendFile;
+ yield writeFunc(filePath, this._buffer, { encoding: 'utf8' });
+ return this.emptyBuffer();
+ });
+ }
+ /**
+ * Clears the summary buffer and wipes the summary file
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ clear() {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.emptyBuffer().write({ overwrite: true });
+ });
+ }
+ /**
+ * Returns the current summary buffer as a string
+ *
+ * @returns {string} string of summary buffer
+ */
+ stringify() {
+ return this._buffer;
+ }
+ /**
+ * If the summary buffer is empty
+ *
+ * @returns {boolen} true if the buffer is empty
+ */
+ isEmptyBuffer() {
+ return this._buffer.length === 0;
+ }
+ /**
+ * Resets the summary buffer without writing to summary file
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ emptyBuffer() {
+ this._buffer = '';
+ return this;
+ }
+ /**
+ * Adds raw text to the summary buffer
+ *
+ * @param {string} text content to add
+ * @param {boolean} [addEOL=false] (optional) append an EOL to the raw text (default: false)
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addRaw(text, addEOL = false) {
+ this._buffer += text;
+ return addEOL ? this.addEOL() : this;
+ }
+ /**
+ * Adds the operating system-specific end-of-line marker to the buffer
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addEOL() {
+ return this.addRaw(os_1.EOL);
+ }
+ /**
+ * Adds an HTML codeblock to the summary buffer
+ *
+ * @param {string} code content to render within fenced code block
+ * @param {string} lang (optional) language to syntax highlight code
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addCodeBlock(code, lang) {
+ const attrs = Object.assign({}, (lang && { lang }));
+ const element = this.wrap('pre', this.wrap('code', code), attrs);
+ return this.addRaw(element).addEOL();
+ }
+ /**
+ * Adds an HTML list to the summary buffer
+ *
+ * @param {string[]} items list of items to render
+ * @param {boolean} [ordered=false] (optional) if the rendered list should be ordered or not (default: false)
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addList(items, ordered = false) {
+ const tag = ordered ? 'ol' : 'ul';
+ const listItems = items.map(item => this.wrap('li', item)).join('');
+ const element = this.wrap(tag, listItems);
+ return this.addRaw(element).addEOL();
+ }
+ /**
+ * Adds an HTML table to the summary buffer
+ *
+ * @param {SummaryTableCell[]} rows table rows
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addTable(rows) {
+ const tableBody = rows
+ .map(row => {
+ const cells = row
+ .map(cell => {
+ if (typeof cell === 'string') {
+ return this.wrap('td', cell);
+ }
+ const { header, data, colspan, rowspan } = cell;
+ const tag = header ? 'th' : 'td';
+ const attrs = Object.assign(Object.assign({}, (colspan && { colspan })), (rowspan && { rowspan }));
+ return this.wrap(tag, data, attrs);
+ })
+ .join('');
+ return this.wrap('tr', cells);
+ })
+ .join('');
+ const element = this.wrap('table', tableBody);
+ return this.addRaw(element).addEOL();
+ }
+ /**
+ * Adds a collapsable HTML details element to the summary buffer
+ *
+ * @param {string} label text for the closed state
+ * @param {string} content collapsable content
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addDetails(label, content) {
+ const element = this.wrap('details', this.wrap('summary', label) + content);
+ return this.addRaw(element).addEOL();
+ }
+ /**
+ * Adds an HTML image tag to the summary buffer
+ *
+ * @param {string} src path to the image you to embed
+ * @param {string} alt text description of the image
+ * @param {SummaryImageOptions} options (optional) addition image attributes
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addImage(src, alt, options) {
+ const { width, height } = options || {};
+ const attrs = Object.assign(Object.assign({}, (width && { width })), (height && { height }));
+ const element = this.wrap('img', null, Object.assign({ src, alt }, attrs));
+ return this.addRaw(element).addEOL();
+ }
+ /**
+ * Adds an HTML section heading element
+ *
+ * @param {string} text heading text
+ * @param {number | string} [level=1] (optional) the heading level, default: 1
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addHeading(text, level) {
+ const tag = `h${level}`;
+ const allowedTag = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tag)
+ ? tag
+ : 'h1';
+ const element = this.wrap(allowedTag, text);
+ return this.addRaw(element).addEOL();
+ }
+ /**
+ * Adds an HTML thematic break (
) to the summary buffer
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addSeparator() {
+ const element = this.wrap('hr', null);
+ return this.addRaw(element).addEOL();
+ }
+ /**
+ * Adds an HTML line break (
) to the summary buffer
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addBreak() {
+ const element = this.wrap('br', null);
+ return this.addRaw(element).addEOL();
+ }
+ /**
+ * Adds an HTML blockquote to the summary buffer
+ *
+ * @param {string} text quote text
+ * @param {string} cite (optional) citation url
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addQuote(text, cite) {
+ const attrs = Object.assign({}, (cite && { cite }));
+ const element = this.wrap('blockquote', text, attrs);
+ return this.addRaw(element).addEOL();
+ }
+ /**
+ * Adds an HTML anchor tag to the summary buffer
+ *
+ * @param {string} text link text/content
+ * @param {string} href hyperlink
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addLink(text, href) {
+ const element = this.wrap('a', text, { href });
+ return this.addRaw(element).addEOL();
+ }
+}
+// singleton export
+exports.markdownSummary = new MarkdownSummary();
+//# sourceMappingURL=markdown-summary.js.map
+
+/***/ }),
+
+/***/ 8041:
+/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
+
+"use strict";
+
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.OidcClient = void 0;
+const http_client_1 = __nccwpck_require__(9925);
+const auth_1 = __nccwpck_require__(3702);
+const core_1 = __nccwpck_require__(2186);
+class OidcClient {
+ static createHttpClient(allowRetry = true, maxRetry = 10) {
+ const requestOptions = {
+ allowRetries: allowRetry,
+ maxRetries: maxRetry
+ };
+ return new http_client_1.HttpClient('actions/oidc-client', [new auth_1.BearerCredentialHandler(OidcClient.getRequestToken())], requestOptions);
+ }
+ static getRequestToken() {
+ const token = process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN'];
+ if (!token) {
+ throw new Error('Unable to get ACTIONS_ID_TOKEN_REQUEST_TOKEN env variable');
+ }
+ return token;
+ }
+ static getIDTokenUrl() {
+ const runtimeUrl = process.env['ACTIONS_ID_TOKEN_REQUEST_URL'];
+ if (!runtimeUrl) {
+ throw new Error('Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable');
+ }
+ return runtimeUrl;
+ }
+ static getCall(id_token_url) {
+ var _a;
+ return __awaiter(this, void 0, void 0, function* () {
+ const httpclient = OidcClient.createHttpClient();
+ const res = yield httpclient
+ .getJson(id_token_url)
+ .catch(error => {
+ throw new Error(`Failed to get ID Token. \n
+ Error Code : ${error.statusCode}\n
+ Error Message: ${error.result.message}`);
+ });
+ const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value;
+ if (!id_token) {
+ throw new Error('Response json body do not have ID Token field');
+ }
+ return id_token;
+ });
+ }
+ static getIDToken(audience) {
+ return __awaiter(this, void 0, void 0, function* () {
+ try {
+ // New ID Token is requested from action service
+ let id_token_url = OidcClient.getIDTokenUrl();
+ if (audience) {
+ const encodedAudience = encodeURIComponent(audience);
+ id_token_url = `${id_token_url}&audience=${encodedAudience}`;
+ }
+ core_1.debug(`ID token url is ${id_token_url}`);
+ const id_token = yield OidcClient.getCall(id_token_url);
+ core_1.setSecret(id_token);
+ return id_token;
+ }
+ catch (error) {
+ throw new Error(`Error message: ${error.message}`);
+ }
+ });
+ }
+}
+exports.OidcClient = OidcClient;
+//# sourceMappingURL=oidc-utils.js.map
+
+/***/ }),
+
/***/ 5278:
/***/ ((__unused_webpack_module, exports) => {
@@ -4946,6 +4745,7 @@ exports.issueCommand = issueCommand;
// We use any as a valid input type
/* eslint-disable @typescript-eslint/no-explicit-any */
Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.toCommandProperties = exports.toCommandValue = void 0;
/**
* Sanitizes an input into a string so it can be passed into issueCommand safely
* @param input input to sanitize into a string
@@ -4960,6 +4760,26 @@ function toCommandValue(input) {
return JSON.stringify(input);
}
exports.toCommandValue = toCommandValue;
+/**
+ *
+ * @param annotationProperties
+ * @returns The command properties to send with the actual annotation command
+ * See IssueCommandProperties: https://github.com/actions/runner/blob/main/src/Runner.Worker/ActionCommandManager.cs#L646
+ */
+function toCommandProperties(annotationProperties) {
+ if (!Object.keys(annotationProperties).length) {
+ return {};
+ }
+ return {
+ title: annotationProperties.title,
+ file: annotationProperties.file,
+ line: annotationProperties.startLine,
+ endLine: annotationProperties.endLine,
+ col: annotationProperties.startColumn,
+ endColumn: annotationProperties.endColumn
+ };
+}
+exports.toCommandProperties = toCommandProperties;
//# sourceMappingURL=utils.js.map
/***/ }),
@@ -5697,6 +5517,682 @@ class ExecState extends events.EventEmitter {
}
//# sourceMappingURL=toolrunner.js.map
+/***/ }),
+
+/***/ 3702:
+/***/ ((__unused_webpack_module, exports) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+class BasicCredentialHandler {
+ constructor(username, password) {
+ this.username = username;
+ this.password = password;
+ }
+ prepareRequest(options) {
+ options.headers['Authorization'] =
+ 'Basic ' +
+ Buffer.from(this.username + ':' + this.password).toString('base64');
+ }
+ // This handler cannot handle 401
+ canHandleAuthentication(response) {
+ return false;
+ }
+ handleAuthentication(httpClient, requestInfo, objs) {
+ return null;
+ }
+}
+exports.BasicCredentialHandler = BasicCredentialHandler;
+class BearerCredentialHandler {
+ constructor(token) {
+ this.token = token;
+ }
+ // currently implements pre-authorization
+ // TODO: support preAuth = false where it hooks on 401
+ prepareRequest(options) {
+ options.headers['Authorization'] = 'Bearer ' + this.token;
+ }
+ // This handler cannot handle 401
+ canHandleAuthentication(response) {
+ return false;
+ }
+ handleAuthentication(httpClient, requestInfo, objs) {
+ return null;
+ }
+}
+exports.BearerCredentialHandler = BearerCredentialHandler;
+class PersonalAccessTokenCredentialHandler {
+ constructor(token) {
+ this.token = token;
+ }
+ // currently implements pre-authorization
+ // TODO: support preAuth = false where it hooks on 401
+ prepareRequest(options) {
+ options.headers['Authorization'] =
+ 'Basic ' + Buffer.from('PAT:' + this.token).toString('base64');
+ }
+ // This handler cannot handle 401
+ canHandleAuthentication(response) {
+ return false;
+ }
+ handleAuthentication(httpClient, requestInfo, objs) {
+ return null;
+ }
+}
+exports.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHandler;
+
+
+/***/ }),
+
+/***/ 9925:
+/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+const http = __nccwpck_require__(3685);
+const https = __nccwpck_require__(5687);
+const pm = __nccwpck_require__(6443);
+let tunnel;
+var HttpCodes;
+(function (HttpCodes) {
+ HttpCodes[HttpCodes["OK"] = 200] = "OK";
+ HttpCodes[HttpCodes["MultipleChoices"] = 300] = "MultipleChoices";
+ HttpCodes[HttpCodes["MovedPermanently"] = 301] = "MovedPermanently";
+ HttpCodes[HttpCodes["ResourceMoved"] = 302] = "ResourceMoved";
+ HttpCodes[HttpCodes["SeeOther"] = 303] = "SeeOther";
+ HttpCodes[HttpCodes["NotModified"] = 304] = "NotModified";
+ HttpCodes[HttpCodes["UseProxy"] = 305] = "UseProxy";
+ HttpCodes[HttpCodes["SwitchProxy"] = 306] = "SwitchProxy";
+ HttpCodes[HttpCodes["TemporaryRedirect"] = 307] = "TemporaryRedirect";
+ HttpCodes[HttpCodes["PermanentRedirect"] = 308] = "PermanentRedirect";
+ HttpCodes[HttpCodes["BadRequest"] = 400] = "BadRequest";
+ HttpCodes[HttpCodes["Unauthorized"] = 401] = "Unauthorized";
+ HttpCodes[HttpCodes["PaymentRequired"] = 402] = "PaymentRequired";
+ HttpCodes[HttpCodes["Forbidden"] = 403] = "Forbidden";
+ HttpCodes[HttpCodes["NotFound"] = 404] = "NotFound";
+ HttpCodes[HttpCodes["MethodNotAllowed"] = 405] = "MethodNotAllowed";
+ HttpCodes[HttpCodes["NotAcceptable"] = 406] = "NotAcceptable";
+ HttpCodes[HttpCodes["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
+ HttpCodes[HttpCodes["RequestTimeout"] = 408] = "RequestTimeout";
+ HttpCodes[HttpCodes["Conflict"] = 409] = "Conflict";
+ HttpCodes[HttpCodes["Gone"] = 410] = "Gone";
+ HttpCodes[HttpCodes["TooManyRequests"] = 429] = "TooManyRequests";
+ HttpCodes[HttpCodes["InternalServerError"] = 500] = "InternalServerError";
+ HttpCodes[HttpCodes["NotImplemented"] = 501] = "NotImplemented";
+ HttpCodes[HttpCodes["BadGateway"] = 502] = "BadGateway";
+ HttpCodes[HttpCodes["ServiceUnavailable"] = 503] = "ServiceUnavailable";
+ HttpCodes[HttpCodes["GatewayTimeout"] = 504] = "GatewayTimeout";
+})(HttpCodes = exports.HttpCodes || (exports.HttpCodes = {}));
+var Headers;
+(function (Headers) {
+ Headers["Accept"] = "accept";
+ Headers["ContentType"] = "content-type";
+})(Headers = exports.Headers || (exports.Headers = {}));
+var MediaTypes;
+(function (MediaTypes) {
+ MediaTypes["ApplicationJson"] = "application/json";
+})(MediaTypes = exports.MediaTypes || (exports.MediaTypes = {}));
+/**
+ * Returns the proxy URL, depending upon the supplied url and proxy environment variables.
+ * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
+ */
+function getProxyUrl(serverUrl) {
+ let proxyUrl = pm.getProxyUrl(new URL(serverUrl));
+ return proxyUrl ? proxyUrl.href : '';
+}
+exports.getProxyUrl = getProxyUrl;
+const HttpRedirectCodes = [
+ HttpCodes.MovedPermanently,
+ HttpCodes.ResourceMoved,
+ HttpCodes.SeeOther,
+ HttpCodes.TemporaryRedirect,
+ HttpCodes.PermanentRedirect
+];
+const HttpResponseRetryCodes = [
+ HttpCodes.BadGateway,
+ HttpCodes.ServiceUnavailable,
+ HttpCodes.GatewayTimeout
+];
+const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD'];
+const ExponentialBackoffCeiling = 10;
+const ExponentialBackoffTimeSlice = 5;
+class HttpClientError extends Error {
+ constructor(message, statusCode) {
+ super(message);
+ this.name = 'HttpClientError';
+ this.statusCode = statusCode;
+ Object.setPrototypeOf(this, HttpClientError.prototype);
+ }
+}
+exports.HttpClientError = HttpClientError;
+class HttpClientResponse {
+ constructor(message) {
+ this.message = message;
+ }
+ readBody() {
+ return new Promise(async (resolve, reject) => {
+ let output = Buffer.alloc(0);
+ this.message.on('data', (chunk) => {
+ output = Buffer.concat([output, chunk]);
+ });
+ this.message.on('end', () => {
+ resolve(output.toString());
+ });
+ });
+ }
+}
+exports.HttpClientResponse = HttpClientResponse;
+function isHttps(requestUrl) {
+ let parsedUrl = new URL(requestUrl);
+ return parsedUrl.protocol === 'https:';
+}
+exports.isHttps = isHttps;
+class HttpClient {
+ constructor(userAgent, handlers, requestOptions) {
+ this._ignoreSslError = false;
+ this._allowRedirects = true;
+ this._allowRedirectDowngrade = false;
+ this._maxRedirects = 50;
+ this._allowRetries = false;
+ this._maxRetries = 1;
+ this._keepAlive = false;
+ this._disposed = false;
+ this.userAgent = userAgent;
+ this.handlers = handlers || [];
+ this.requestOptions = requestOptions;
+ if (requestOptions) {
+ if (requestOptions.ignoreSslError != null) {
+ this._ignoreSslError = requestOptions.ignoreSslError;
+ }
+ this._socketTimeout = requestOptions.socketTimeout;
+ if (requestOptions.allowRedirects != null) {
+ this._allowRedirects = requestOptions.allowRedirects;
+ }
+ if (requestOptions.allowRedirectDowngrade != null) {
+ this._allowRedirectDowngrade = requestOptions.allowRedirectDowngrade;
+ }
+ if (requestOptions.maxRedirects != null) {
+ this._maxRedirects = Math.max(requestOptions.maxRedirects, 0);
+ }
+ if (requestOptions.keepAlive != null) {
+ this._keepAlive = requestOptions.keepAlive;
+ }
+ if (requestOptions.allowRetries != null) {
+ this._allowRetries = requestOptions.allowRetries;
+ }
+ if (requestOptions.maxRetries != null) {
+ this._maxRetries = requestOptions.maxRetries;
+ }
+ }
+ }
+ options(requestUrl, additionalHeaders) {
+ return this.request('OPTIONS', requestUrl, null, additionalHeaders || {});
+ }
+ get(requestUrl, additionalHeaders) {
+ return this.request('GET', requestUrl, null, additionalHeaders || {});
+ }
+ del(requestUrl, additionalHeaders) {
+ return this.request('DELETE', requestUrl, null, additionalHeaders || {});
+ }
+ post(requestUrl, data, additionalHeaders) {
+ return this.request('POST', requestUrl, data, additionalHeaders || {});
+ }
+ patch(requestUrl, data, additionalHeaders) {
+ return this.request('PATCH', requestUrl, data, additionalHeaders || {});
+ }
+ put(requestUrl, data, additionalHeaders) {
+ return this.request('PUT', requestUrl, data, additionalHeaders || {});
+ }
+ head(requestUrl, additionalHeaders) {
+ return this.request('HEAD', requestUrl, null, additionalHeaders || {});
+ }
+ sendStream(verb, requestUrl, stream, additionalHeaders) {
+ return this.request(verb, requestUrl, stream, additionalHeaders);
+ }
+ /**
+ * Gets a typed object from an endpoint
+ * Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise
+ */
+ async getJson(requestUrl, additionalHeaders = {}) {
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ let res = await this.get(requestUrl, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ }
+ async postJson(requestUrl, obj, additionalHeaders = {}) {
+ let data = JSON.stringify(obj, null, 2);
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
+ let res = await this.post(requestUrl, data, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ }
+ async putJson(requestUrl, obj, additionalHeaders = {}) {
+ let data = JSON.stringify(obj, null, 2);
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
+ let res = await this.put(requestUrl, data, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ }
+ async patchJson(requestUrl, obj, additionalHeaders = {}) {
+ let data = JSON.stringify(obj, null, 2);
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
+ let res = await this.patch(requestUrl, data, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ }
+ /**
+ * Makes a raw http request.
+ * All other methods such as get, post, patch, and request ultimately call this.
+ * Prefer get, del, post and patch
+ */
+ async request(verb, requestUrl, data, headers) {
+ if (this._disposed) {
+ throw new Error('Client has already been disposed.');
+ }
+ let parsedUrl = new URL(requestUrl);
+ let info = this._prepareRequest(verb, parsedUrl, headers);
+ // Only perform retries on reads since writes may not be idempotent.
+ let maxTries = this._allowRetries && RetryableHttpVerbs.indexOf(verb) != -1
+ ? this._maxRetries + 1
+ : 1;
+ let numTries = 0;
+ let response;
+ while (numTries < maxTries) {
+ response = await this.requestRaw(info, data);
+ // Check if it's an authentication challenge
+ if (response &&
+ response.message &&
+ response.message.statusCode === HttpCodes.Unauthorized) {
+ let authenticationHandler;
+ for (let i = 0; i < this.handlers.length; i++) {
+ if (this.handlers[i].canHandleAuthentication(response)) {
+ authenticationHandler = this.handlers[i];
+ break;
+ }
+ }
+ if (authenticationHandler) {
+ return authenticationHandler.handleAuthentication(this, info, data);
+ }
+ else {
+ // We have received an unauthorized response but have no handlers to handle it.
+ // Let the response return to the caller.
+ return response;
+ }
+ }
+ let redirectsRemaining = this._maxRedirects;
+ while (HttpRedirectCodes.indexOf(response.message.statusCode) != -1 &&
+ this._allowRedirects &&
+ redirectsRemaining > 0) {
+ const redirectUrl = response.message.headers['location'];
+ if (!redirectUrl) {
+ // if there's no location to redirect to, we won't
+ break;
+ }
+ let parsedRedirectUrl = new URL(redirectUrl);
+ if (parsedUrl.protocol == 'https:' &&
+ parsedUrl.protocol != parsedRedirectUrl.protocol &&
+ !this._allowRedirectDowngrade) {
+ throw new Error('Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.');
+ }
+ // we need to finish reading the response before reassigning response
+ // which will leak the open socket.
+ await response.readBody();
+ // strip authorization header if redirected to a different hostname
+ if (parsedRedirectUrl.hostname !== parsedUrl.hostname) {
+ for (let header in headers) {
+ // header names are case insensitive
+ if (header.toLowerCase() === 'authorization') {
+ delete headers[header];
+ }
+ }
+ }
+ // let's make the request with the new redirectUrl
+ info = this._prepareRequest(verb, parsedRedirectUrl, headers);
+ response = await this.requestRaw(info, data);
+ redirectsRemaining--;
+ }
+ if (HttpResponseRetryCodes.indexOf(response.message.statusCode) == -1) {
+ // If not a retry code, return immediately instead of retrying
+ return response;
+ }
+ numTries += 1;
+ if (numTries < maxTries) {
+ await response.readBody();
+ await this._performExponentialBackoff(numTries);
+ }
+ }
+ return response;
+ }
+ /**
+ * Needs to be called if keepAlive is set to true in request options.
+ */
+ dispose() {
+ if (this._agent) {
+ this._agent.destroy();
+ }
+ this._disposed = true;
+ }
+ /**
+ * Raw request.
+ * @param info
+ * @param data
+ */
+ requestRaw(info, data) {
+ return new Promise((resolve, reject) => {
+ let callbackForResult = function (err, res) {
+ if (err) {
+ reject(err);
+ }
+ resolve(res);
+ };
+ this.requestRawWithCallback(info, data, callbackForResult);
+ });
+ }
+ /**
+ * Raw request with callback.
+ * @param info
+ * @param data
+ * @param onResult
+ */
+ requestRawWithCallback(info, data, onResult) {
+ let socket;
+ if (typeof data === 'string') {
+ info.options.headers['Content-Length'] = Buffer.byteLength(data, 'utf8');
+ }
+ let callbackCalled = false;
+ let handleResult = (err, res) => {
+ if (!callbackCalled) {
+ callbackCalled = true;
+ onResult(err, res);
+ }
+ };
+ let req = info.httpModule.request(info.options, (msg) => {
+ let res = new HttpClientResponse(msg);
+ handleResult(null, res);
+ });
+ req.on('socket', sock => {
+ socket = sock;
+ });
+ // If we ever get disconnected, we want the socket to timeout eventually
+ req.setTimeout(this._socketTimeout || 3 * 60000, () => {
+ if (socket) {
+ socket.end();
+ }
+ handleResult(new Error('Request timeout: ' + info.options.path), null);
+ });
+ req.on('error', function (err) {
+ // err has statusCode property
+ // res should have headers
+ handleResult(err, null);
+ });
+ if (data && typeof data === 'string') {
+ req.write(data, 'utf8');
+ }
+ if (data && typeof data !== 'string') {
+ data.on('close', function () {
+ req.end();
+ });
+ data.pipe(req);
+ }
+ else {
+ req.end();
+ }
+ }
+ /**
+ * Gets an http agent. This function is useful when you need an http agent that handles
+ * routing through a proxy server - depending upon the url and proxy environment variables.
+ * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
+ */
+ getAgent(serverUrl) {
+ let parsedUrl = new URL(serverUrl);
+ return this._getAgent(parsedUrl);
+ }
+ _prepareRequest(method, requestUrl, headers) {
+ const info = {};
+ info.parsedUrl = requestUrl;
+ const usingSsl = info.parsedUrl.protocol === 'https:';
+ info.httpModule = usingSsl ? https : http;
+ const defaultPort = usingSsl ? 443 : 80;
+ info.options = {};
+ info.options.host = info.parsedUrl.hostname;
+ info.options.port = info.parsedUrl.port
+ ? parseInt(info.parsedUrl.port)
+ : defaultPort;
+ info.options.path =
+ (info.parsedUrl.pathname || '') + (info.parsedUrl.search || '');
+ info.options.method = method;
+ info.options.headers = this._mergeHeaders(headers);
+ if (this.userAgent != null) {
+ info.options.headers['user-agent'] = this.userAgent;
+ }
+ info.options.agent = this._getAgent(info.parsedUrl);
+ // gives handlers an opportunity to participate
+ if (this.handlers) {
+ this.handlers.forEach(handler => {
+ handler.prepareRequest(info.options);
+ });
+ }
+ return info;
+ }
+ _mergeHeaders(headers) {
+ const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
+ if (this.requestOptions && this.requestOptions.headers) {
+ return Object.assign({}, lowercaseKeys(this.requestOptions.headers), lowercaseKeys(headers));
+ }
+ return lowercaseKeys(headers || {});
+ }
+ _getExistingOrDefaultHeader(additionalHeaders, header, _default) {
+ const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
+ let clientHeader;
+ if (this.requestOptions && this.requestOptions.headers) {
+ clientHeader = lowercaseKeys(this.requestOptions.headers)[header];
+ }
+ return additionalHeaders[header] || clientHeader || _default;
+ }
+ _getAgent(parsedUrl) {
+ let agent;
+ let proxyUrl = pm.getProxyUrl(parsedUrl);
+ let useProxy = proxyUrl && proxyUrl.hostname;
+ if (this._keepAlive && useProxy) {
+ agent = this._proxyAgent;
+ }
+ if (this._keepAlive && !useProxy) {
+ agent = this._agent;
+ }
+ // if agent is already assigned use that agent.
+ if (!!agent) {
+ return agent;
+ }
+ const usingSsl = parsedUrl.protocol === 'https:';
+ let maxSockets = 100;
+ if (!!this.requestOptions) {
+ maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets;
+ }
+ if (useProxy) {
+ // If using proxy, need tunnel
+ if (!tunnel) {
+ tunnel = __nccwpck_require__(4294);
+ }
+ const agentOptions = {
+ maxSockets: maxSockets,
+ keepAlive: this._keepAlive,
+ proxy: {
+ ...((proxyUrl.username || proxyUrl.password) && {
+ proxyAuth: `${proxyUrl.username}:${proxyUrl.password}`
+ }),
+ host: proxyUrl.hostname,
+ port: proxyUrl.port
+ }
+ };
+ let tunnelAgent;
+ const overHttps = proxyUrl.protocol === 'https:';
+ if (usingSsl) {
+ tunnelAgent = overHttps ? tunnel.httpsOverHttps : tunnel.httpsOverHttp;
+ }
+ else {
+ tunnelAgent = overHttps ? tunnel.httpOverHttps : tunnel.httpOverHttp;
+ }
+ agent = tunnelAgent(agentOptions);
+ this._proxyAgent = agent;
+ }
+ // if reusing agent across request and tunneling agent isn't assigned create a new agent
+ if (this._keepAlive && !agent) {
+ const options = { keepAlive: this._keepAlive, maxSockets: maxSockets };
+ agent = usingSsl ? new https.Agent(options) : new http.Agent(options);
+ this._agent = agent;
+ }
+ // if not using private agent and tunnel agent isn't setup then use global agent
+ if (!agent) {
+ agent = usingSsl ? https.globalAgent : http.globalAgent;
+ }
+ if (usingSsl && this._ignoreSslError) {
+ // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process
+ // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options
+ // we have to cast it to any and change it directly
+ agent.options = Object.assign(agent.options || {}, {
+ rejectUnauthorized: false
+ });
+ }
+ return agent;
+ }
+ _performExponentialBackoff(retryNumber) {
+ retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber);
+ const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber);
+ return new Promise(resolve => setTimeout(() => resolve(), ms));
+ }
+ static dateTimeDeserializer(key, value) {
+ if (typeof value === 'string') {
+ let a = new Date(value);
+ if (!isNaN(a.valueOf())) {
+ return a;
+ }
+ }
+ return value;
+ }
+ async _processResponse(res, options) {
+ return new Promise(async (resolve, reject) => {
+ const statusCode = res.message.statusCode;
+ const response = {
+ statusCode: statusCode,
+ result: null,
+ headers: {}
+ };
+ // not found leads to null obj returned
+ if (statusCode == HttpCodes.NotFound) {
+ resolve(response);
+ }
+ let obj;
+ let contents;
+ // get the result from the body
+ try {
+ contents = await res.readBody();
+ if (contents && contents.length > 0) {
+ if (options && options.deserializeDates) {
+ obj = JSON.parse(contents, HttpClient.dateTimeDeserializer);
+ }
+ else {
+ obj = JSON.parse(contents);
+ }
+ response.result = obj;
+ }
+ response.headers = res.message.headers;
+ }
+ catch (err) {
+ // Invalid resource (contents not json); leaving result obj null
+ }
+ // note that 3xx redirects are handled by the http layer.
+ if (statusCode > 299) {
+ let msg;
+ // if exception/error in body, attempt to get better error
+ if (obj && obj.message) {
+ msg = obj.message;
+ }
+ else if (contents && contents.length > 0) {
+ // it may be the case that the exception is in the body message as string
+ msg = contents;
+ }
+ else {
+ msg = 'Failed request: (' + statusCode + ')';
+ }
+ let err = new HttpClientError(msg, statusCode);
+ err.result = response.result;
+ reject(err);
+ }
+ else {
+ resolve(response);
+ }
+ });
+ }
+}
+exports.HttpClient = HttpClient;
+
+
+/***/ }),
+
+/***/ 6443:
+/***/ ((__unused_webpack_module, exports) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+function getProxyUrl(reqUrl) {
+ let usingSsl = reqUrl.protocol === 'https:';
+ let proxyUrl;
+ if (checkBypass(reqUrl)) {
+ return proxyUrl;
+ }
+ let proxyVar;
+ if (usingSsl) {
+ proxyVar = process.env['https_proxy'] || process.env['HTTPS_PROXY'];
+ }
+ else {
+ proxyVar = process.env['http_proxy'] || process.env['HTTP_PROXY'];
+ }
+ if (proxyVar) {
+ proxyUrl = new URL(proxyVar);
+ }
+ return proxyUrl;
+}
+exports.getProxyUrl = getProxyUrl;
+function checkBypass(reqUrl) {
+ if (!reqUrl.hostname) {
+ return false;
+ }
+ let noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || '';
+ if (!noProxy) {
+ return false;
+ }
+ // Determine the request port
+ let reqPort;
+ if (reqUrl.port) {
+ reqPort = Number(reqUrl.port);
+ }
+ else if (reqUrl.protocol === 'http:') {
+ reqPort = 80;
+ }
+ else if (reqUrl.protocol === 'https:') {
+ reqPort = 443;
+ }
+ // Format the request hostname and hostname with port
+ let upperReqHosts = [reqUrl.hostname.toUpperCase()];
+ if (typeof reqPort === 'number') {
+ upperReqHosts.push(`${upperReqHosts[0]}:${reqPort}`);
+ }
+ // Compare request host against noproxy
+ for (let upperNoProxyItem of noProxy
+ .split(',')
+ .map(x => x.trim().toUpperCase())
+ .filter(x => x)) {
+ if (upperReqHosts.some(x => x === upperNoProxyItem)) {
+ return true;
+ }
+ }
+ return false;
+}
+exports.checkBypass = checkBypass;
+
+
/***/ }),
/***/ 1962:
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 3c417588..cdd0f706 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -214,8 +214,8 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(7320);
-const auth_1 = __nccwpck_require__(7093);
+const http_client_1 = __nccwpck_require__(9925);
+const auth_1 = __nccwpck_require__(3702);
const crypto = __importStar(__nccwpck_require__(6113));
const fs = __importStar(__nccwpck_require__(7147));
const url_1 = __nccwpck_require__(7310);
@@ -647,7 +647,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(7320);
+const http_client_1 = __nccwpck_require__(9925);
const storage_blob_1 = __nccwpck_require__(4100);
const buffer = __importStar(__nccwpck_require__(4300));
const fs = __importStar(__nccwpck_require__(7147));
@@ -885,7 +885,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(7320);
+const http_client_1 = __nccwpck_require__(9925);
const constants_1 = __nccwpck_require__(8840);
function isSuccessStatusCode(statusCode) {
if (!statusCode) {
@@ -2290,682 +2290,6 @@ class SearchState {
exports.SearchState = SearchState;
//# sourceMappingURL=internal-search-state.js.map
-/***/ }),
-
-/***/ 7093:
-/***/ ((__unused_webpack_module, exports) => {
-
-"use strict";
-
-Object.defineProperty(exports, "__esModule", ({ value: true }));
-class BasicCredentialHandler {
- constructor(username, password) {
- this.username = username;
- this.password = password;
- }
- prepareRequest(options) {
- options.headers['Authorization'] =
- 'Basic ' +
- Buffer.from(this.username + ':' + this.password).toString('base64');
- }
- // This handler cannot handle 401
- canHandleAuthentication(response) {
- return false;
- }
- handleAuthentication(httpClient, requestInfo, objs) {
- return null;
- }
-}
-exports.BasicCredentialHandler = BasicCredentialHandler;
-class BearerCredentialHandler {
- constructor(token) {
- this.token = token;
- }
- // currently implements pre-authorization
- // TODO: support preAuth = false where it hooks on 401
- prepareRequest(options) {
- options.headers['Authorization'] = 'Bearer ' + this.token;
- }
- // This handler cannot handle 401
- canHandleAuthentication(response) {
- return false;
- }
- handleAuthentication(httpClient, requestInfo, objs) {
- return null;
- }
-}
-exports.BearerCredentialHandler = BearerCredentialHandler;
-class PersonalAccessTokenCredentialHandler {
- constructor(token) {
- this.token = token;
- }
- // currently implements pre-authorization
- // TODO: support preAuth = false where it hooks on 401
- prepareRequest(options) {
- options.headers['Authorization'] =
- 'Basic ' + Buffer.from('PAT:' + this.token).toString('base64');
- }
- // This handler cannot handle 401
- canHandleAuthentication(response) {
- return false;
- }
- handleAuthentication(httpClient, requestInfo, objs) {
- return null;
- }
-}
-exports.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHandler;
-
-
-/***/ }),
-
-/***/ 7320:
-/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
-
-"use strict";
-
-Object.defineProperty(exports, "__esModule", ({ value: true }));
-const http = __nccwpck_require__(3685);
-const https = __nccwpck_require__(5687);
-const pm = __nccwpck_require__(7326);
-let tunnel;
-var HttpCodes;
-(function (HttpCodes) {
- HttpCodes[HttpCodes["OK"] = 200] = "OK";
- HttpCodes[HttpCodes["MultipleChoices"] = 300] = "MultipleChoices";
- HttpCodes[HttpCodes["MovedPermanently"] = 301] = "MovedPermanently";
- HttpCodes[HttpCodes["ResourceMoved"] = 302] = "ResourceMoved";
- HttpCodes[HttpCodes["SeeOther"] = 303] = "SeeOther";
- HttpCodes[HttpCodes["NotModified"] = 304] = "NotModified";
- HttpCodes[HttpCodes["UseProxy"] = 305] = "UseProxy";
- HttpCodes[HttpCodes["SwitchProxy"] = 306] = "SwitchProxy";
- HttpCodes[HttpCodes["TemporaryRedirect"] = 307] = "TemporaryRedirect";
- HttpCodes[HttpCodes["PermanentRedirect"] = 308] = "PermanentRedirect";
- HttpCodes[HttpCodes["BadRequest"] = 400] = "BadRequest";
- HttpCodes[HttpCodes["Unauthorized"] = 401] = "Unauthorized";
- HttpCodes[HttpCodes["PaymentRequired"] = 402] = "PaymentRequired";
- HttpCodes[HttpCodes["Forbidden"] = 403] = "Forbidden";
- HttpCodes[HttpCodes["NotFound"] = 404] = "NotFound";
- HttpCodes[HttpCodes["MethodNotAllowed"] = 405] = "MethodNotAllowed";
- HttpCodes[HttpCodes["NotAcceptable"] = 406] = "NotAcceptable";
- HttpCodes[HttpCodes["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
- HttpCodes[HttpCodes["RequestTimeout"] = 408] = "RequestTimeout";
- HttpCodes[HttpCodes["Conflict"] = 409] = "Conflict";
- HttpCodes[HttpCodes["Gone"] = 410] = "Gone";
- HttpCodes[HttpCodes["TooManyRequests"] = 429] = "TooManyRequests";
- HttpCodes[HttpCodes["InternalServerError"] = 500] = "InternalServerError";
- HttpCodes[HttpCodes["NotImplemented"] = 501] = "NotImplemented";
- HttpCodes[HttpCodes["BadGateway"] = 502] = "BadGateway";
- HttpCodes[HttpCodes["ServiceUnavailable"] = 503] = "ServiceUnavailable";
- HttpCodes[HttpCodes["GatewayTimeout"] = 504] = "GatewayTimeout";
-})(HttpCodes = exports.HttpCodes || (exports.HttpCodes = {}));
-var Headers;
-(function (Headers) {
- Headers["Accept"] = "accept";
- Headers["ContentType"] = "content-type";
-})(Headers = exports.Headers || (exports.Headers = {}));
-var MediaTypes;
-(function (MediaTypes) {
- MediaTypes["ApplicationJson"] = "application/json";
-})(MediaTypes = exports.MediaTypes || (exports.MediaTypes = {}));
-/**
- * Returns the proxy URL, depending upon the supplied url and proxy environment variables.
- * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
- */
-function getProxyUrl(serverUrl) {
- let proxyUrl = pm.getProxyUrl(new URL(serverUrl));
- return proxyUrl ? proxyUrl.href : '';
-}
-exports.getProxyUrl = getProxyUrl;
-const HttpRedirectCodes = [
- HttpCodes.MovedPermanently,
- HttpCodes.ResourceMoved,
- HttpCodes.SeeOther,
- HttpCodes.TemporaryRedirect,
- HttpCodes.PermanentRedirect
-];
-const HttpResponseRetryCodes = [
- HttpCodes.BadGateway,
- HttpCodes.ServiceUnavailable,
- HttpCodes.GatewayTimeout
-];
-const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD'];
-const ExponentialBackoffCeiling = 10;
-const ExponentialBackoffTimeSlice = 5;
-class HttpClientError extends Error {
- constructor(message, statusCode) {
- super(message);
- this.name = 'HttpClientError';
- this.statusCode = statusCode;
- Object.setPrototypeOf(this, HttpClientError.prototype);
- }
-}
-exports.HttpClientError = HttpClientError;
-class HttpClientResponse {
- constructor(message) {
- this.message = message;
- }
- readBody() {
- return new Promise(async (resolve, reject) => {
- let output = Buffer.alloc(0);
- this.message.on('data', (chunk) => {
- output = Buffer.concat([output, chunk]);
- });
- this.message.on('end', () => {
- resolve(output.toString());
- });
- });
- }
-}
-exports.HttpClientResponse = HttpClientResponse;
-function isHttps(requestUrl) {
- let parsedUrl = new URL(requestUrl);
- return parsedUrl.protocol === 'https:';
-}
-exports.isHttps = isHttps;
-class HttpClient {
- constructor(userAgent, handlers, requestOptions) {
- this._ignoreSslError = false;
- this._allowRedirects = true;
- this._allowRedirectDowngrade = false;
- this._maxRedirects = 50;
- this._allowRetries = false;
- this._maxRetries = 1;
- this._keepAlive = false;
- this._disposed = false;
- this.userAgent = userAgent;
- this.handlers = handlers || [];
- this.requestOptions = requestOptions;
- if (requestOptions) {
- if (requestOptions.ignoreSslError != null) {
- this._ignoreSslError = requestOptions.ignoreSslError;
- }
- this._socketTimeout = requestOptions.socketTimeout;
- if (requestOptions.allowRedirects != null) {
- this._allowRedirects = requestOptions.allowRedirects;
- }
- if (requestOptions.allowRedirectDowngrade != null) {
- this._allowRedirectDowngrade = requestOptions.allowRedirectDowngrade;
- }
- if (requestOptions.maxRedirects != null) {
- this._maxRedirects = Math.max(requestOptions.maxRedirects, 0);
- }
- if (requestOptions.keepAlive != null) {
- this._keepAlive = requestOptions.keepAlive;
- }
- if (requestOptions.allowRetries != null) {
- this._allowRetries = requestOptions.allowRetries;
- }
- if (requestOptions.maxRetries != null) {
- this._maxRetries = requestOptions.maxRetries;
- }
- }
- }
- options(requestUrl, additionalHeaders) {
- return this.request('OPTIONS', requestUrl, null, additionalHeaders || {});
- }
- get(requestUrl, additionalHeaders) {
- return this.request('GET', requestUrl, null, additionalHeaders || {});
- }
- del(requestUrl, additionalHeaders) {
- return this.request('DELETE', requestUrl, null, additionalHeaders || {});
- }
- post(requestUrl, data, additionalHeaders) {
- return this.request('POST', requestUrl, data, additionalHeaders || {});
- }
- patch(requestUrl, data, additionalHeaders) {
- return this.request('PATCH', requestUrl, data, additionalHeaders || {});
- }
- put(requestUrl, data, additionalHeaders) {
- return this.request('PUT', requestUrl, data, additionalHeaders || {});
- }
- head(requestUrl, additionalHeaders) {
- return this.request('HEAD', requestUrl, null, additionalHeaders || {});
- }
- sendStream(verb, requestUrl, stream, additionalHeaders) {
- return this.request(verb, requestUrl, stream, additionalHeaders);
- }
- /**
- * Gets a typed object from an endpoint
- * Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise
- */
- async getJson(requestUrl, additionalHeaders = {}) {
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- let res = await this.get(requestUrl, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
- }
- async postJson(requestUrl, obj, additionalHeaders = {}) {
- let data = JSON.stringify(obj, null, 2);
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
- let res = await this.post(requestUrl, data, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
- }
- async putJson(requestUrl, obj, additionalHeaders = {}) {
- let data = JSON.stringify(obj, null, 2);
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
- let res = await this.put(requestUrl, data, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
- }
- async patchJson(requestUrl, obj, additionalHeaders = {}) {
- let data = JSON.stringify(obj, null, 2);
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
- let res = await this.patch(requestUrl, data, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
- }
- /**
- * Makes a raw http request.
- * All other methods such as get, post, patch, and request ultimately call this.
- * Prefer get, del, post and patch
- */
- async request(verb, requestUrl, data, headers) {
- if (this._disposed) {
- throw new Error('Client has already been disposed.');
- }
- let parsedUrl = new URL(requestUrl);
- let info = this._prepareRequest(verb, parsedUrl, headers);
- // Only perform retries on reads since writes may not be idempotent.
- let maxTries = this._allowRetries && RetryableHttpVerbs.indexOf(verb) != -1
- ? this._maxRetries + 1
- : 1;
- let numTries = 0;
- let response;
- while (numTries < maxTries) {
- response = await this.requestRaw(info, data);
- // Check if it's an authentication challenge
- if (response &&
- response.message &&
- response.message.statusCode === HttpCodes.Unauthorized) {
- let authenticationHandler;
- for (let i = 0; i < this.handlers.length; i++) {
- if (this.handlers[i].canHandleAuthentication(response)) {
- authenticationHandler = this.handlers[i];
- break;
- }
- }
- if (authenticationHandler) {
- return authenticationHandler.handleAuthentication(this, info, data);
- }
- else {
- // We have received an unauthorized response but have no handlers to handle it.
- // Let the response return to the caller.
- return response;
- }
- }
- let redirectsRemaining = this._maxRedirects;
- while (HttpRedirectCodes.indexOf(response.message.statusCode) != -1 &&
- this._allowRedirects &&
- redirectsRemaining > 0) {
- const redirectUrl = response.message.headers['location'];
- if (!redirectUrl) {
- // if there's no location to redirect to, we won't
- break;
- }
- let parsedRedirectUrl = new URL(redirectUrl);
- if (parsedUrl.protocol == 'https:' &&
- parsedUrl.protocol != parsedRedirectUrl.protocol &&
- !this._allowRedirectDowngrade) {
- throw new Error('Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.');
- }
- // we need to finish reading the response before reassigning response
- // which will leak the open socket.
- await response.readBody();
- // strip authorization header if redirected to a different hostname
- if (parsedRedirectUrl.hostname !== parsedUrl.hostname) {
- for (let header in headers) {
- // header names are case insensitive
- if (header.toLowerCase() === 'authorization') {
- delete headers[header];
- }
- }
- }
- // let's make the request with the new redirectUrl
- info = this._prepareRequest(verb, parsedRedirectUrl, headers);
- response = await this.requestRaw(info, data);
- redirectsRemaining--;
- }
- if (HttpResponseRetryCodes.indexOf(response.message.statusCode) == -1) {
- // If not a retry code, return immediately instead of retrying
- return response;
- }
- numTries += 1;
- if (numTries < maxTries) {
- await response.readBody();
- await this._performExponentialBackoff(numTries);
- }
- }
- return response;
- }
- /**
- * Needs to be called if keepAlive is set to true in request options.
- */
- dispose() {
- if (this._agent) {
- this._agent.destroy();
- }
- this._disposed = true;
- }
- /**
- * Raw request.
- * @param info
- * @param data
- */
- requestRaw(info, data) {
- return new Promise((resolve, reject) => {
- let callbackForResult = function (err, res) {
- if (err) {
- reject(err);
- }
- resolve(res);
- };
- this.requestRawWithCallback(info, data, callbackForResult);
- });
- }
- /**
- * Raw request with callback.
- * @param info
- * @param data
- * @param onResult
- */
- requestRawWithCallback(info, data, onResult) {
- let socket;
- if (typeof data === 'string') {
- info.options.headers['Content-Length'] = Buffer.byteLength(data, 'utf8');
- }
- let callbackCalled = false;
- let handleResult = (err, res) => {
- if (!callbackCalled) {
- callbackCalled = true;
- onResult(err, res);
- }
- };
- let req = info.httpModule.request(info.options, (msg) => {
- let res = new HttpClientResponse(msg);
- handleResult(null, res);
- });
- req.on('socket', sock => {
- socket = sock;
- });
- // If we ever get disconnected, we want the socket to timeout eventually
- req.setTimeout(this._socketTimeout || 3 * 60000, () => {
- if (socket) {
- socket.end();
- }
- handleResult(new Error('Request timeout: ' + info.options.path), null);
- });
- req.on('error', function (err) {
- // err has statusCode property
- // res should have headers
- handleResult(err, null);
- });
- if (data && typeof data === 'string') {
- req.write(data, 'utf8');
- }
- if (data && typeof data !== 'string') {
- data.on('close', function () {
- req.end();
- });
- data.pipe(req);
- }
- else {
- req.end();
- }
- }
- /**
- * Gets an http agent. This function is useful when you need an http agent that handles
- * routing through a proxy server - depending upon the url and proxy environment variables.
- * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
- */
- getAgent(serverUrl) {
- let parsedUrl = new URL(serverUrl);
- return this._getAgent(parsedUrl);
- }
- _prepareRequest(method, requestUrl, headers) {
- const info = {};
- info.parsedUrl = requestUrl;
- const usingSsl = info.parsedUrl.protocol === 'https:';
- info.httpModule = usingSsl ? https : http;
- const defaultPort = usingSsl ? 443 : 80;
- info.options = {};
- info.options.host = info.parsedUrl.hostname;
- info.options.port = info.parsedUrl.port
- ? parseInt(info.parsedUrl.port)
- : defaultPort;
- info.options.path =
- (info.parsedUrl.pathname || '') + (info.parsedUrl.search || '');
- info.options.method = method;
- info.options.headers = this._mergeHeaders(headers);
- if (this.userAgent != null) {
- info.options.headers['user-agent'] = this.userAgent;
- }
- info.options.agent = this._getAgent(info.parsedUrl);
- // gives handlers an opportunity to participate
- if (this.handlers) {
- this.handlers.forEach(handler => {
- handler.prepareRequest(info.options);
- });
- }
- return info;
- }
- _mergeHeaders(headers) {
- const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
- if (this.requestOptions && this.requestOptions.headers) {
- return Object.assign({}, lowercaseKeys(this.requestOptions.headers), lowercaseKeys(headers));
- }
- return lowercaseKeys(headers || {});
- }
- _getExistingOrDefaultHeader(additionalHeaders, header, _default) {
- const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
- let clientHeader;
- if (this.requestOptions && this.requestOptions.headers) {
- clientHeader = lowercaseKeys(this.requestOptions.headers)[header];
- }
- return additionalHeaders[header] || clientHeader || _default;
- }
- _getAgent(parsedUrl) {
- let agent;
- let proxyUrl = pm.getProxyUrl(parsedUrl);
- let useProxy = proxyUrl && proxyUrl.hostname;
- if (this._keepAlive && useProxy) {
- agent = this._proxyAgent;
- }
- if (this._keepAlive && !useProxy) {
- agent = this._agent;
- }
- // if agent is already assigned use that agent.
- if (!!agent) {
- return agent;
- }
- const usingSsl = parsedUrl.protocol === 'https:';
- let maxSockets = 100;
- if (!!this.requestOptions) {
- maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets;
- }
- if (useProxy) {
- // If using proxy, need tunnel
- if (!tunnel) {
- tunnel = __nccwpck_require__(4294);
- }
- const agentOptions = {
- maxSockets: maxSockets,
- keepAlive: this._keepAlive,
- proxy: {
- ...((proxyUrl.username || proxyUrl.password) && {
- proxyAuth: `${proxyUrl.username}:${proxyUrl.password}`
- }),
- host: proxyUrl.hostname,
- port: proxyUrl.port
- }
- };
- let tunnelAgent;
- const overHttps = proxyUrl.protocol === 'https:';
- if (usingSsl) {
- tunnelAgent = overHttps ? tunnel.httpsOverHttps : tunnel.httpsOverHttp;
- }
- else {
- tunnelAgent = overHttps ? tunnel.httpOverHttps : tunnel.httpOverHttp;
- }
- agent = tunnelAgent(agentOptions);
- this._proxyAgent = agent;
- }
- // if reusing agent across request and tunneling agent isn't assigned create a new agent
- if (this._keepAlive && !agent) {
- const options = { keepAlive: this._keepAlive, maxSockets: maxSockets };
- agent = usingSsl ? new https.Agent(options) : new http.Agent(options);
- this._agent = agent;
- }
- // if not using private agent and tunnel agent isn't setup then use global agent
- if (!agent) {
- agent = usingSsl ? https.globalAgent : http.globalAgent;
- }
- if (usingSsl && this._ignoreSslError) {
- // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process
- // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options
- // we have to cast it to any and change it directly
- agent.options = Object.assign(agent.options || {}, {
- rejectUnauthorized: false
- });
- }
- return agent;
- }
- _performExponentialBackoff(retryNumber) {
- retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber);
- const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber);
- return new Promise(resolve => setTimeout(() => resolve(), ms));
- }
- static dateTimeDeserializer(key, value) {
- if (typeof value === 'string') {
- let a = new Date(value);
- if (!isNaN(a.valueOf())) {
- return a;
- }
- }
- return value;
- }
- async _processResponse(res, options) {
- return new Promise(async (resolve, reject) => {
- const statusCode = res.message.statusCode;
- const response = {
- statusCode: statusCode,
- result: null,
- headers: {}
- };
- // not found leads to null obj returned
- if (statusCode == HttpCodes.NotFound) {
- resolve(response);
- }
- let obj;
- let contents;
- // get the result from the body
- try {
- contents = await res.readBody();
- if (contents && contents.length > 0) {
- if (options && options.deserializeDates) {
- obj = JSON.parse(contents, HttpClient.dateTimeDeserializer);
- }
- else {
- obj = JSON.parse(contents);
- }
- response.result = obj;
- }
- response.headers = res.message.headers;
- }
- catch (err) {
- // Invalid resource (contents not json); leaving result obj null
- }
- // note that 3xx redirects are handled by the http layer.
- if (statusCode > 299) {
- let msg;
- // if exception/error in body, attempt to get better error
- if (obj && obj.message) {
- msg = obj.message;
- }
- else if (contents && contents.length > 0) {
- // it may be the case that the exception is in the body message as string
- msg = contents;
- }
- else {
- msg = 'Failed request: (' + statusCode + ')';
- }
- let err = new HttpClientError(msg, statusCode);
- err.result = response.result;
- reject(err);
- }
- else {
- resolve(response);
- }
- });
- }
-}
-exports.HttpClient = HttpClient;
-
-
-/***/ }),
-
-/***/ 7326:
-/***/ ((__unused_webpack_module, exports) => {
-
-"use strict";
-
-Object.defineProperty(exports, "__esModule", ({ value: true }));
-function getProxyUrl(reqUrl) {
- let usingSsl = reqUrl.protocol === 'https:';
- let proxyUrl;
- if (checkBypass(reqUrl)) {
- return proxyUrl;
- }
- let proxyVar;
- if (usingSsl) {
- proxyVar = process.env['https_proxy'] || process.env['HTTPS_PROXY'];
- }
- else {
- proxyVar = process.env['http_proxy'] || process.env['HTTP_PROXY'];
- }
- if (proxyVar) {
- proxyUrl = new URL(proxyVar);
- }
- return proxyUrl;
-}
-exports.getProxyUrl = getProxyUrl;
-function checkBypass(reqUrl) {
- if (!reqUrl.hostname) {
- return false;
- }
- let noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || '';
- if (!noProxy) {
- return false;
- }
- // Determine the request port
- let reqPort;
- if (reqUrl.port) {
- reqPort = Number(reqUrl.port);
- }
- else if (reqUrl.protocol === 'http:') {
- reqPort = 80;
- }
- else if (reqUrl.protocol === 'https:') {
- reqPort = 443;
- }
- // Format the request hostname and hostname with port
- let upperReqHosts = [reqUrl.hostname.toUpperCase()];
- if (typeof reqPort === 'number') {
- upperReqHosts.push(`${upperReqHosts[0]}:${reqPort}`);
- }
- // Compare request host against noproxy
- for (let upperNoProxyItem of noProxy
- .split(',')
- .map(x => x.trim().toUpperCase())
- .filter(x => x)) {
- if (upperReqHosts.some(x => x === upperNoProxyItem)) {
- return true;
- }
- }
- return false;
-}
-exports.checkBypass = checkBypass;
-
-
/***/ }),
/***/ 3771:
@@ -4576,14 +3900,27 @@ function coerce (version, options) {
"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
- if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
- result["default"] = mod;
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.issue = exports.issueCommand = void 0;
const os = __importStar(__nccwpck_require__(2037));
const utils_1 = __nccwpck_require__(5278);
/**
@@ -4662,6 +3999,25 @@ function escapeProperty(s) {
"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
@@ -4671,19 +4027,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
-var __importStar = (this && this.__importStar) || function (mod) {
- if (mod && mod.__esModule) return mod;
- var result = {};
- if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
- result["default"] = mod;
- return result;
-};
Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.getIDToken = exports.getState = exports.saveState = exports.group = exports.endGroup = exports.startGroup = exports.info = exports.notice = exports.warning = exports.error = exports.debug = exports.isDebug = exports.setFailed = exports.setCommandEcho = exports.setOutput = exports.getBooleanInput = exports.getMultilineInput = exports.getInput = exports.addPath = exports.setSecret = exports.exportVariable = exports.ExitCode = void 0;
const command_1 = __nccwpck_require__(7351);
const file_command_1 = __nccwpck_require__(717);
const utils_1 = __nccwpck_require__(5278);
const os = __importStar(__nccwpck_require__(2037));
const path = __importStar(__nccwpck_require__(1017));
+const oidc_utils_1 = __nccwpck_require__(8041);
/**
* The code to exit an action
*/
@@ -4745,7 +4096,9 @@ function addPath(inputPath) {
}
exports.addPath = addPath;
/**
- * Gets the value of an input. The value is also trimmed.
+ * Gets the value of an input.
+ * Unless trimWhitespace is set to false in InputOptions, the value is also trimmed.
+ * Returns an empty string if the value is not defined.
*
* @param name name of the input to get
* @param options optional. See InputOptions.
@@ -4756,9 +4109,49 @@ function getInput(name, options) {
if (options && options.required && !val) {
throw new Error(`Input required and not supplied: ${name}`);
}
+ if (options && options.trimWhitespace === false) {
+ return val;
+ }
return val.trim();
}
exports.getInput = getInput;
+/**
+ * Gets the values of an multiline input. Each value is also trimmed.
+ *
+ * @param name name of the input to get
+ * @param options optional. See InputOptions.
+ * @returns string[]
+ *
+ */
+function getMultilineInput(name, options) {
+ const inputs = getInput(name, options)
+ .split('\n')
+ .filter(x => x !== '');
+ return inputs;
+}
+exports.getMultilineInput = getMultilineInput;
+/**
+ * Gets the input value of the boolean type in the YAML 1.2 "core schema" specification.
+ * Support boolean input list: `true | True | TRUE | false | False | FALSE` .
+ * The return value is also in boolean type.
+ * ref: https://yaml.org/spec/1.2/spec.html#id2804923
+ *
+ * @param name name of the input to get
+ * @param options optional. See InputOptions.
+ * @returns boolean
+ */
+function getBooleanInput(name, options) {
+ const trueValue = ['true', 'True', 'TRUE'];
+ const falseValue = ['false', 'False', 'FALSE'];
+ const val = getInput(name, options);
+ if (trueValue.includes(val))
+ return true;
+ if (falseValue.includes(val))
+ return false;
+ throw new TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${name}\n` +
+ `Support boolean input list: \`true | True | TRUE | false | False | FALSE\``);
+}
+exports.getBooleanInput = getBooleanInput;
/**
* Sets the value of an output.
*
@@ -4767,6 +4160,7 @@ exports.getInput = getInput;
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function setOutput(name, value) {
+ process.stdout.write(os.EOL);
command_1.issueCommand('set-output', { name }, value);
}
exports.setOutput = setOutput;
@@ -4813,19 +4207,30 @@ exports.debug = debug;
/**
* Adds an error issue
* @param message error issue message. Errors will be converted to string via toString()
+ * @param properties optional properties to add to the annotation.
*/
-function error(message) {
- command_1.issue('error', message instanceof Error ? message.toString() : message);
+function error(message, properties = {}) {
+ command_1.issueCommand('error', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message);
}
exports.error = error;
/**
- * Adds an warning issue
+ * Adds a warning issue
* @param message warning issue message. Errors will be converted to string via toString()
+ * @param properties optional properties to add to the annotation.
*/
-function warning(message) {
- command_1.issue('warning', message instanceof Error ? message.toString() : message);
+function warning(message, properties = {}) {
+ command_1.issueCommand('warning', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message);
}
exports.warning = warning;
+/**
+ * Adds a notice issue
+ * @param message notice issue message. Errors will be converted to string via toString()
+ * @param properties optional properties to add to the annotation.
+ */
+function notice(message, properties = {}) {
+ command_1.issueCommand('notice', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message);
+}
+exports.notice = notice;
/**
* Writes info to log with console.log.
* @param message info message
@@ -4898,6 +4303,17 @@ function getState(name) {
return process.env[`STATE_${name}`] || '';
}
exports.getState = getState;
+function getIDToken(aud) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return yield oidc_utils_1.OidcClient.getIDToken(aud);
+ });
+}
+exports.getIDToken = getIDToken;
+/**
+ * Markdown summary exports
+ */
+var markdown_summary_1 = __nccwpck_require__(8042);
+Object.defineProperty(exports, "markdownSummary", ({ enumerable: true, get: function () { return markdown_summary_1.markdownSummary; } }));
//# sourceMappingURL=core.js.map
/***/ }),
@@ -4908,14 +4324,27 @@ exports.getState = getState;
"use strict";
// For internal use, subject to change.
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
- if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
- result["default"] = mod;
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.issueCommand = void 0;
// We use any as a valid input type
/* eslint-disable @typescript-eslint/no-explicit-any */
const fs = __importStar(__nccwpck_require__(7147));
@@ -4938,6 +4367,376 @@ exports.issueCommand = issueCommand;
/***/ }),
+/***/ 8042:
+/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
+
+"use strict";
+
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.markdownSummary = exports.SUMMARY_DOCS_URL = exports.SUMMARY_ENV_VAR = void 0;
+const os_1 = __nccwpck_require__(2037);
+const fs_1 = __nccwpck_require__(7147);
+const { access, appendFile, writeFile } = fs_1.promises;
+exports.SUMMARY_ENV_VAR = 'GITHUB_STEP_SUMMARY';
+exports.SUMMARY_DOCS_URL = 'https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary';
+class MarkdownSummary {
+ constructor() {
+ this._buffer = '';
+ }
+ /**
+ * Finds the summary file path from the environment, rejects if env var is not found or file does not exist
+ * Also checks r/w permissions.
+ *
+ * @returns step summary file path
+ */
+ filePath() {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (this._filePath) {
+ return this._filePath;
+ }
+ const pathFromEnv = process.env[exports.SUMMARY_ENV_VAR];
+ if (!pathFromEnv) {
+ throw new Error(`Unable to find environment variable for $${exports.SUMMARY_ENV_VAR}. Check if your runtime environment supports markdown summaries.`);
+ }
+ try {
+ yield access(pathFromEnv, fs_1.constants.R_OK | fs_1.constants.W_OK);
+ }
+ catch (_a) {
+ throw new Error(`Unable to access summary file: '${pathFromEnv}'. Check if the file has correct read/write permissions.`);
+ }
+ this._filePath = pathFromEnv;
+ return this._filePath;
+ });
+ }
+ /**
+ * Wraps content in an HTML tag, adding any HTML attributes
+ *
+ * @param {string} tag HTML tag to wrap
+ * @param {string | null} content content within the tag
+ * @param {[attribute: string]: string} attrs key-value list of HTML attributes to add
+ *
+ * @returns {string} content wrapped in HTML element
+ */
+ wrap(tag, content, attrs = {}) {
+ const htmlAttrs = Object.entries(attrs)
+ .map(([key, value]) => ` ${key}="${value}"`)
+ .join('');
+ if (!content) {
+ return `<${tag}${htmlAttrs}>`;
+ }
+ return `<${tag}${htmlAttrs}>${content}${tag}>`;
+ }
+ /**
+ * Writes text in the buffer to the summary buffer file and empties buffer. Will append by default.
+ *
+ * @param {SummaryWriteOptions} [options] (optional) options for write operation
+ *
+ * @returns {Promise} markdown summary instance
+ */
+ write(options) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const overwrite = !!(options === null || options === void 0 ? void 0 : options.overwrite);
+ const filePath = yield this.filePath();
+ const writeFunc = overwrite ? writeFile : appendFile;
+ yield writeFunc(filePath, this._buffer, { encoding: 'utf8' });
+ return this.emptyBuffer();
+ });
+ }
+ /**
+ * Clears the summary buffer and wipes the summary file
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ clear() {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.emptyBuffer().write({ overwrite: true });
+ });
+ }
+ /**
+ * Returns the current summary buffer as a string
+ *
+ * @returns {string} string of summary buffer
+ */
+ stringify() {
+ return this._buffer;
+ }
+ /**
+ * If the summary buffer is empty
+ *
+ * @returns {boolen} true if the buffer is empty
+ */
+ isEmptyBuffer() {
+ return this._buffer.length === 0;
+ }
+ /**
+ * Resets the summary buffer without writing to summary file
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ emptyBuffer() {
+ this._buffer = '';
+ return this;
+ }
+ /**
+ * Adds raw text to the summary buffer
+ *
+ * @param {string} text content to add
+ * @param {boolean} [addEOL=false] (optional) append an EOL to the raw text (default: false)
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addRaw(text, addEOL = false) {
+ this._buffer += text;
+ return addEOL ? this.addEOL() : this;
+ }
+ /**
+ * Adds the operating system-specific end-of-line marker to the buffer
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addEOL() {
+ return this.addRaw(os_1.EOL);
+ }
+ /**
+ * Adds an HTML codeblock to the summary buffer
+ *
+ * @param {string} code content to render within fenced code block
+ * @param {string} lang (optional) language to syntax highlight code
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addCodeBlock(code, lang) {
+ const attrs = Object.assign({}, (lang && { lang }));
+ const element = this.wrap('pre', this.wrap('code', code), attrs);
+ return this.addRaw(element).addEOL();
+ }
+ /**
+ * Adds an HTML list to the summary buffer
+ *
+ * @param {string[]} items list of items to render
+ * @param {boolean} [ordered=false] (optional) if the rendered list should be ordered or not (default: false)
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addList(items, ordered = false) {
+ const tag = ordered ? 'ol' : 'ul';
+ const listItems = items.map(item => this.wrap('li', item)).join('');
+ const element = this.wrap(tag, listItems);
+ return this.addRaw(element).addEOL();
+ }
+ /**
+ * Adds an HTML table to the summary buffer
+ *
+ * @param {SummaryTableCell[]} rows table rows
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addTable(rows) {
+ const tableBody = rows
+ .map(row => {
+ const cells = row
+ .map(cell => {
+ if (typeof cell === 'string') {
+ return this.wrap('td', cell);
+ }
+ const { header, data, colspan, rowspan } = cell;
+ const tag = header ? 'th' : 'td';
+ const attrs = Object.assign(Object.assign({}, (colspan && { colspan })), (rowspan && { rowspan }));
+ return this.wrap(tag, data, attrs);
+ })
+ .join('');
+ return this.wrap('tr', cells);
+ })
+ .join('');
+ const element = this.wrap('table', tableBody);
+ return this.addRaw(element).addEOL();
+ }
+ /**
+ * Adds a collapsable HTML details element to the summary buffer
+ *
+ * @param {string} label text for the closed state
+ * @param {string} content collapsable content
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addDetails(label, content) {
+ const element = this.wrap('details', this.wrap('summary', label) + content);
+ return this.addRaw(element).addEOL();
+ }
+ /**
+ * Adds an HTML image tag to the summary buffer
+ *
+ * @param {string} src path to the image you to embed
+ * @param {string} alt text description of the image
+ * @param {SummaryImageOptions} options (optional) addition image attributes
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addImage(src, alt, options) {
+ const { width, height } = options || {};
+ const attrs = Object.assign(Object.assign({}, (width && { width })), (height && { height }));
+ const element = this.wrap('img', null, Object.assign({ src, alt }, attrs));
+ return this.addRaw(element).addEOL();
+ }
+ /**
+ * Adds an HTML section heading element
+ *
+ * @param {string} text heading text
+ * @param {number | string} [level=1] (optional) the heading level, default: 1
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addHeading(text, level) {
+ const tag = `h${level}`;
+ const allowedTag = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tag)
+ ? tag
+ : 'h1';
+ const element = this.wrap(allowedTag, text);
+ return this.addRaw(element).addEOL();
+ }
+ /**
+ * Adds an HTML thematic break (
) to the summary buffer
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addSeparator() {
+ const element = this.wrap('hr', null);
+ return this.addRaw(element).addEOL();
+ }
+ /**
+ * Adds an HTML line break (
) to the summary buffer
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addBreak() {
+ const element = this.wrap('br', null);
+ return this.addRaw(element).addEOL();
+ }
+ /**
+ * Adds an HTML blockquote to the summary buffer
+ *
+ * @param {string} text quote text
+ * @param {string} cite (optional) citation url
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addQuote(text, cite) {
+ const attrs = Object.assign({}, (cite && { cite }));
+ const element = this.wrap('blockquote', text, attrs);
+ return this.addRaw(element).addEOL();
+ }
+ /**
+ * Adds an HTML anchor tag to the summary buffer
+ *
+ * @param {string} text link text/content
+ * @param {string} href hyperlink
+ *
+ * @returns {MarkdownSummary} markdown summary instance
+ */
+ addLink(text, href) {
+ const element = this.wrap('a', text, { href });
+ return this.addRaw(element).addEOL();
+ }
+}
+// singleton export
+exports.markdownSummary = new MarkdownSummary();
+//# sourceMappingURL=markdown-summary.js.map
+
+/***/ }),
+
+/***/ 8041:
+/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
+
+"use strict";
+
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.OidcClient = void 0;
+const http_client_1 = __nccwpck_require__(9925);
+const auth_1 = __nccwpck_require__(3702);
+const core_1 = __nccwpck_require__(2186);
+class OidcClient {
+ static createHttpClient(allowRetry = true, maxRetry = 10) {
+ const requestOptions = {
+ allowRetries: allowRetry,
+ maxRetries: maxRetry
+ };
+ return new http_client_1.HttpClient('actions/oidc-client', [new auth_1.BearerCredentialHandler(OidcClient.getRequestToken())], requestOptions);
+ }
+ static getRequestToken() {
+ const token = process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN'];
+ if (!token) {
+ throw new Error('Unable to get ACTIONS_ID_TOKEN_REQUEST_TOKEN env variable');
+ }
+ return token;
+ }
+ static getIDTokenUrl() {
+ const runtimeUrl = process.env['ACTIONS_ID_TOKEN_REQUEST_URL'];
+ if (!runtimeUrl) {
+ throw new Error('Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable');
+ }
+ return runtimeUrl;
+ }
+ static getCall(id_token_url) {
+ var _a;
+ return __awaiter(this, void 0, void 0, function* () {
+ const httpclient = OidcClient.createHttpClient();
+ const res = yield httpclient
+ .getJson(id_token_url)
+ .catch(error => {
+ throw new Error(`Failed to get ID Token. \n
+ Error Code : ${error.statusCode}\n
+ Error Message: ${error.result.message}`);
+ });
+ const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value;
+ if (!id_token) {
+ throw new Error('Response json body do not have ID Token field');
+ }
+ return id_token;
+ });
+ }
+ static getIDToken(audience) {
+ return __awaiter(this, void 0, void 0, function* () {
+ try {
+ // New ID Token is requested from action service
+ let id_token_url = OidcClient.getIDTokenUrl();
+ if (audience) {
+ const encodedAudience = encodeURIComponent(audience);
+ id_token_url = `${id_token_url}&audience=${encodedAudience}`;
+ }
+ core_1.debug(`ID token url is ${id_token_url}`);
+ const id_token = yield OidcClient.getCall(id_token_url);
+ core_1.setSecret(id_token);
+ return id_token;
+ }
+ catch (error) {
+ throw new Error(`Error message: ${error.message}`);
+ }
+ });
+ }
+}
+exports.OidcClient = OidcClient;
+//# sourceMappingURL=oidc-utils.js.map
+
+/***/ }),
+
/***/ 5278:
/***/ ((__unused_webpack_module, exports) => {
@@ -4946,6 +4745,7 @@ exports.issueCommand = issueCommand;
// We use any as a valid input type
/* eslint-disable @typescript-eslint/no-explicit-any */
Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.toCommandProperties = exports.toCommandValue = void 0;
/**
* Sanitizes an input into a string so it can be passed into issueCommand safely
* @param input input to sanitize into a string
@@ -4960,6 +4760,26 @@ function toCommandValue(input) {
return JSON.stringify(input);
}
exports.toCommandValue = toCommandValue;
+/**
+ *
+ * @param annotationProperties
+ * @returns The command properties to send with the actual annotation command
+ * See IssueCommandProperties: https://github.com/actions/runner/blob/main/src/Runner.Worker/ActionCommandManager.cs#L646
+ */
+function toCommandProperties(annotationProperties) {
+ if (!Object.keys(annotationProperties).length) {
+ return {};
+ }
+ return {
+ title: annotationProperties.title,
+ file: annotationProperties.file,
+ line: annotationProperties.startLine,
+ endLine: annotationProperties.endLine,
+ col: annotationProperties.startColumn,
+ endColumn: annotationProperties.endColumn
+ };
+}
+exports.toCommandProperties = toCommandProperties;
//# sourceMappingURL=utils.js.map
/***/ }),
@@ -6884,6 +6704,72 @@ class SearchState {
exports.SearchState = SearchState;
//# sourceMappingURL=internal-search-state.js.map
+/***/ }),
+
+/***/ 3702:
+/***/ ((__unused_webpack_module, exports) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+class BasicCredentialHandler {
+ constructor(username, password) {
+ this.username = username;
+ this.password = password;
+ }
+ prepareRequest(options) {
+ options.headers['Authorization'] =
+ 'Basic ' +
+ Buffer.from(this.username + ':' + this.password).toString('base64');
+ }
+ // This handler cannot handle 401
+ canHandleAuthentication(response) {
+ return false;
+ }
+ handleAuthentication(httpClient, requestInfo, objs) {
+ return null;
+ }
+}
+exports.BasicCredentialHandler = BasicCredentialHandler;
+class BearerCredentialHandler {
+ constructor(token) {
+ this.token = token;
+ }
+ // currently implements pre-authorization
+ // TODO: support preAuth = false where it hooks on 401
+ prepareRequest(options) {
+ options.headers['Authorization'] = 'Bearer ' + this.token;
+ }
+ // This handler cannot handle 401
+ canHandleAuthentication(response) {
+ return false;
+ }
+ handleAuthentication(httpClient, requestInfo, objs) {
+ return null;
+ }
+}
+exports.BearerCredentialHandler = BearerCredentialHandler;
+class PersonalAccessTokenCredentialHandler {
+ constructor(token) {
+ this.token = token;
+ }
+ // currently implements pre-authorization
+ // TODO: support preAuth = false where it hooks on 401
+ prepareRequest(options) {
+ options.headers['Authorization'] =
+ 'Basic ' + Buffer.from('PAT:' + this.token).toString('base64');
+ }
+ // This handler cannot handle 401
+ canHandleAuthentication(response) {
+ return false;
+ }
+ handleAuthentication(httpClient, requestInfo, objs) {
+ return null;
+ }
+}
+exports.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHandler;
+
+
/***/ }),
/***/ 9925:
@@ -6892,7 +6778,6 @@ exports.SearchState = SearchState;
"use strict";
Object.defineProperty(exports, "__esModule", ({ value: true }));
-const url = __nccwpck_require__(7310);
const http = __nccwpck_require__(3685);
const https = __nccwpck_require__(5687);
const pm = __nccwpck_require__(6443);
@@ -6941,7 +6826,7 @@ var MediaTypes;
* @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
*/
function getProxyUrl(serverUrl) {
- let proxyUrl = pm.getProxyUrl(url.parse(serverUrl));
+ let proxyUrl = pm.getProxyUrl(new URL(serverUrl));
return proxyUrl ? proxyUrl.href : '';
}
exports.getProxyUrl = getProxyUrl;
@@ -6960,6 +6845,15 @@ const HttpResponseRetryCodes = [
const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD'];
const ExponentialBackoffCeiling = 10;
const ExponentialBackoffTimeSlice = 5;
+class HttpClientError extends Error {
+ constructor(message, statusCode) {
+ super(message);
+ this.name = 'HttpClientError';
+ this.statusCode = statusCode;
+ Object.setPrototypeOf(this, HttpClientError.prototype);
+ }
+}
+exports.HttpClientError = HttpClientError;
class HttpClientResponse {
constructor(message) {
this.message = message;
@@ -6978,7 +6872,7 @@ class HttpClientResponse {
}
exports.HttpClientResponse = HttpClientResponse;
function isHttps(requestUrl) {
- let parsedUrl = url.parse(requestUrl);
+ let parsedUrl = new URL(requestUrl);
return parsedUrl.protocol === 'https:';
}
exports.isHttps = isHttps;
@@ -7083,7 +6977,7 @@ class HttpClient {
if (this._disposed) {
throw new Error('Client has already been disposed.');
}
- let parsedUrl = url.parse(requestUrl);
+ let parsedUrl = new URL(requestUrl);
let info = this._prepareRequest(verb, parsedUrl, headers);
// Only perform retries on reads since writes may not be idempotent.
let maxTries = this._allowRetries && RetryableHttpVerbs.indexOf(verb) != -1
@@ -7122,7 +7016,7 @@ class HttpClient {
// if there's no location to redirect to, we won't
break;
}
- let parsedRedirectUrl = url.parse(redirectUrl);
+ let parsedRedirectUrl = new URL(redirectUrl);
if (parsedUrl.protocol == 'https:' &&
parsedUrl.protocol != parsedRedirectUrl.protocol &&
!this._allowRedirectDowngrade) {
@@ -7238,7 +7132,7 @@ class HttpClient {
* @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
*/
getAgent(serverUrl) {
- let parsedUrl = url.parse(serverUrl);
+ let parsedUrl = new URL(serverUrl);
return this._getAgent(parsedUrl);
}
_prepareRequest(method, requestUrl, headers) {
@@ -7311,7 +7205,9 @@ class HttpClient {
maxSockets: maxSockets,
keepAlive: this._keepAlive,
proxy: {
- proxyAuth: proxyUrl.auth,
+ ...((proxyUrl.username || proxyUrl.password) && {
+ proxyAuth: `${proxyUrl.username}:${proxyUrl.password}`
+ }),
host: proxyUrl.hostname,
port: proxyUrl.port
}
@@ -7406,12 +7302,8 @@ class HttpClient {
else {
msg = 'Failed request: (' + statusCode + ')';
}
- let err = new Error(msg);
- // attach statusCode and body obj (if available) to the error object
- err['statusCode'] = statusCode;
- if (response.result) {
- err['result'] = response.result;
- }
+ let err = new HttpClientError(msg, statusCode);
+ err.result = response.result;
reject(err);
}
else {
@@ -7426,12 +7318,11 @@ exports.HttpClient = HttpClient;
/***/ }),
/***/ 6443:
-/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
+/***/ ((__unused_webpack_module, exports) => {
"use strict";
Object.defineProperty(exports, "__esModule", ({ value: true }));
-const url = __nccwpck_require__(7310);
function getProxyUrl(reqUrl) {
let usingSsl = reqUrl.protocol === 'https:';
let proxyUrl;
@@ -7446,7 +7337,7 @@ function getProxyUrl(reqUrl) {
proxyVar = process.env['http_proxy'] || process.env['HTTP_PROXY'];
}
if (proxyVar) {
- proxyUrl = url.parse(proxyVar);
+ proxyUrl = new URL(proxyVar);
}
return proxyUrl;
}
@@ -63974,7 +63865,7 @@ 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) {
+function findPyPyVersion(versionSpec, architecture, updateEnvironment) {
return __awaiter(this, void 0, void 0, function* () {
let resolvedPyPyVersion = '';
let resolvedPythonVersion = '';
@@ -63993,10 +63884,12 @@ function findPyPyVersion(versionSpec, architecture) {
const binaryExtension = utils_1.IS_WINDOWS ? '.exe' : '';
const pythonPath = path.join(utils_1.IS_WINDOWS ? installDir : _binDir, `python${binaryExtension}`);
const pythonLocation = pypyInstall.getPyPyBinaryPath(installDir);
- core.exportVariable('pythonLocation', installDir);
- core.exportVariable('PKG_CONFIG_PATH', pythonLocation + '/lib/pkgconfig');
- core.addPath(pythonLocation);
- core.addPath(_binDir);
+ if (updateEnvironment) {
+ core.exportVariable('pythonLocation', installDir);
+ core.exportVariable('PKG_CONFIG_PATH', pythonLocation + '/lib/pkgconfig');
+ core.addPath(pythonLocation);
+ core.addPath(_binDir);
+ }
core.setOutput('python-version', 'pypy' + resolvedPyPyVersion.trim());
core.setOutput('python-path', pythonPath);
return { resolvedPyPyVersion, resolvedPythonVersion };
@@ -64128,7 +64021,7 @@ function binDir(installDir) {
return path.join(installDir, 'bin');
}
}
-function useCpythonVersion(version, architecture) {
+function useCpythonVersion(version, architecture, updateEnvironment) {
return __awaiter(this, void 0, void 0, function* () {
const desugaredVersionSpec = desugarDevVersion(version);
const semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec);
@@ -64149,33 +64042,35 @@ function useCpythonVersion(version, architecture) {
`The list of all available versions can be found here: ${installer.MANIFEST_URL}`
].join(os.EOL));
}
- core.exportVariable('pythonLocation', installDir);
- core.exportVariable('PKG_CONFIG_PATH', installDir + '/lib/pkgconfig');
- if (utils_1.IS_LINUX) {
- const libPath = process.env.LD_LIBRARY_PATH
- ? `:${process.env.LD_LIBRARY_PATH}`
- : '';
- const pyLibPath = path.join(installDir, 'lib');
- if (!libPath.split(':').includes(pyLibPath)) {
- core.exportVariable('LD_LIBRARY_PATH', pyLibPath + libPath);
- }
- }
const _binDir = binDir(installDir);
const binaryExtension = utils_1.IS_WINDOWS ? '.exe' : '';
const pythonPath = path.join(utils_1.IS_WINDOWS ? installDir : _binDir, `python${binaryExtension}`);
- core.addPath(installDir);
- core.addPath(_binDir);
- if (utils_1.IS_WINDOWS) {
- // Add --user directory
- // `installDir` from tool cache should look like $RUNNER_TOOL_CACHE/Python//x64/
- // So if `findLocalTool` succeeded above, we must have a conformant `installDir`
- const version = path.basename(path.dirname(installDir));
- const major = semver.major(version);
- const minor = semver.minor(version);
- const userScriptsDir = path.join(process.env['APPDATA'] || '', 'Python', `Python${major}${minor}`, 'Scripts');
- core.addPath(userScriptsDir);
+ if (updateEnvironment) {
+ core.exportVariable('pythonLocation', installDir);
+ core.exportVariable('PKG_CONFIG_PATH', installDir + '/lib/pkgconfig');
+ if (utils_1.IS_LINUX) {
+ const libPath = process.env.LD_LIBRARY_PATH
+ ? `:${process.env.LD_LIBRARY_PATH}`
+ : '';
+ const pyLibPath = path.join(installDir, 'lib');
+ if (!libPath.split(':').includes(pyLibPath)) {
+ core.exportVariable('LD_LIBRARY_PATH', pyLibPath + libPath);
+ }
+ }
+ core.addPath(installDir);
+ core.addPath(_binDir);
+ if (utils_1.IS_WINDOWS) {
+ // Add --user directory
+ // `installDir` from tool cache should look like $RUNNER_TOOL_CACHE/Python//x64/
+ // So if `findLocalTool` succeeded above, we must have a conformant `installDir`
+ const version = path.basename(path.dirname(installDir));
+ const major = semver.major(version);
+ const minor = semver.minor(version);
+ const userScriptsDir = path.join(process.env['APPDATA'] || '', 'Python', `Python${major}${minor}`, 'Scripts');
+ core.addPath(userScriptsDir);
+ }
+ // On Linux and macOS, pip will create the --user directory and add it to PATH as needed.
}
- // On Linux and macOS, pip will create the --user directory and add it to PATH as needed.
const installed = versionFromPath(installDir);
core.setOutput('python-version', installed);
core.setOutput('python-path', pythonPath);
@@ -64576,13 +64471,14 @@ function run() {
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);
+ const installed = yield finderPyPy.findPyPyVersion(version, arch, updateEnvironment);
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);
+ const installed = yield finder.useCpythonVersion(version, arch, updateEnvironment);
pythonVersion = installed.version;
core.info(`Successfully set up ${installed.impl} (${pythonVersion})`);
}
diff --git a/package-lock.json b/package-lock.json
index d009e435..9e3bc595 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,7 +10,7 @@
"license": "MIT",
"dependencies": {
"@actions/cache": "^2.0.2",
- "@actions/core": "^1.2.3",
+ "@actions/core": "^1.7.0",
"@actions/exec": "^1.1.0",
"@actions/glob": "^0.2.0",
"@actions/io": "^1.0.2",
@@ -55,14 +55,6 @@
"minimatch": "^3.0.4"
}
},
- "node_modules/@actions/cache/node_modules/@actions/http-client": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
- "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
- "dependencies": {
- "tunnel": "0.0.6"
- }
- },
"node_modules/@actions/cache/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@@ -72,9 +64,12 @@
}
},
"node_modules/@actions/core": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz",
- "integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA=="
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.7.0.tgz",
+ "integrity": "sha512-7fPSS7yKOhTpgLMbw7lBLc1QJWvJBBAgyTX2PEhagWcKK8t0H8AKCoPMfnrHqIm5cRYH4QFPqD1/ruhuUE7YcQ==",
+ "dependencies": {
+ "@actions/http-client": "^1.0.11"
+ }
},
"node_modules/@actions/exec": {
"version": "1.1.0",
@@ -94,9 +89,9 @@
}
},
"node_modules/@actions/http-client": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.8.tgz",
- "integrity": "sha512-G4JjJ6f9Hb3Zvejj+ewLLKLf99ZC+9v+yCxoYf9vSyH+WkzPLB2LuUtRMGNkooMqdugGBFStIKXOuvH1W+EctA==",
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
+ "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
"dependencies": {
"tunnel": "0.0.6"
}
@@ -11361,14 +11356,6 @@
"minimatch": "^3.0.4"
}
},
- "@actions/http-client": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
- "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
- "requires": {
- "tunnel": "0.0.6"
- }
- },
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@@ -11377,9 +11364,12 @@
}
},
"@actions/core": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz",
- "integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA=="
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.7.0.tgz",
+ "integrity": "sha512-7fPSS7yKOhTpgLMbw7lBLc1QJWvJBBAgyTX2PEhagWcKK8t0H8AKCoPMfnrHqIm5cRYH4QFPqD1/ruhuUE7YcQ==",
+ "requires": {
+ "@actions/http-client": "^1.0.11"
+ }
},
"@actions/exec": {
"version": "1.1.0",
@@ -11399,9 +11389,9 @@
}
},
"@actions/http-client": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.8.tgz",
- "integrity": "sha512-G4JjJ6f9Hb3Zvejj+ewLLKLf99ZC+9v+yCxoYf9vSyH+WkzPLB2LuUtRMGNkooMqdugGBFStIKXOuvH1W+EctA==",
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
+ "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
"requires": {
"tunnel": "0.0.6"
}
diff --git a/package.json b/package.json
index d7d88f24..d9c4ca31 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,7 @@
"license": "MIT",
"dependencies": {
"@actions/cache": "^2.0.2",
- "@actions/core": "^1.2.3",
+ "@actions/core": "^1.7.0",
"@actions/exec": "^1.1.0",
"@actions/glob": "^0.2.0",
"@actions/io": "^1.0.2",
diff --git a/src/find-pypy.ts b/src/find-pypy.ts
index 630d685c..a1949629 100644
--- a/src/find-pypy.ts
+++ b/src/find-pypy.ts
@@ -20,7 +20,8 @@ interface IPyPyVersionSpec {
export async function findPyPyVersion(
versionSpec: string,
- architecture: string
+ architecture: string,
+ updateEnvironment: boolean
): Promise<{resolvedPyPyVersion: string; resolvedPythonVersion: string}> {
let resolvedPyPyVersion = '';
let resolvedPythonVersion = '';
@@ -54,10 +55,12 @@ export async function findPyPyVersion(
`python${binaryExtension}`
);
const pythonLocation = pypyInstall.getPyPyBinaryPath(installDir);
- core.exportVariable('pythonLocation', installDir);
- core.exportVariable('PKG_CONFIG_PATH', pythonLocation + '/lib/pkgconfig');
- core.addPath(pythonLocation);
- core.addPath(_binDir);
+ if (updateEnvironment) {
+ core.exportVariable('pythonLocation', installDir);
+ core.exportVariable('PKG_CONFIG_PATH', pythonLocation + '/lib/pkgconfig');
+ core.addPath(pythonLocation);
+ core.addPath(_binDir);
+ }
core.setOutput('python-version', 'pypy' + resolvedPyPyVersion.trim());
core.setOutput('python-path', pythonPath);
diff --git a/src/find-python.ts b/src/find-python.ts
index f1dad3a9..96759606 100644
--- a/src/find-python.ts
+++ b/src/find-python.ts
@@ -32,7 +32,8 @@ function binDir(installDir: string): string {
export async function useCpythonVersion(
version: string,
- architecture: string
+ architecture: string,
+ updateEnvironment: boolean
): Promise {
const desugaredVersionSpec = desugarDevVersion(version);
const semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec);
@@ -69,46 +70,47 @@ export async function useCpythonVersion(
);
}
- core.exportVariable('pythonLocation', installDir);
- core.exportVariable('PKG_CONFIG_PATH', installDir + '/lib/pkgconfig');
-
- if (IS_LINUX) {
- const libPath = process.env.LD_LIBRARY_PATH
- ? `:${process.env.LD_LIBRARY_PATH}`
- : '';
- const pyLibPath = path.join(installDir, 'lib');
-
- if (!libPath.split(':').includes(pyLibPath)) {
- core.exportVariable('LD_LIBRARY_PATH', pyLibPath + libPath);
- }
- }
-
const _binDir = binDir(installDir);
const binaryExtension = IS_WINDOWS ? '.exe' : '';
const pythonPath = path.join(
IS_WINDOWS ? installDir : _binDir,
`python${binaryExtension}`
);
- core.addPath(installDir);
- core.addPath(_binDir);
+ if (updateEnvironment) {
+ core.exportVariable('pythonLocation', installDir);
+ core.exportVariable('PKG_CONFIG_PATH', installDir + '/lib/pkgconfig');
- if (IS_WINDOWS) {
- // Add --user directory
- // `installDir` from tool cache should look like $RUNNER_TOOL_CACHE/Python//x64/
- // So if `findLocalTool` succeeded above, we must have a conformant `installDir`
- const version = path.basename(path.dirname(installDir));
- const major = semver.major(version);
- const minor = semver.minor(version);
+ if (IS_LINUX) {
+ const libPath = process.env.LD_LIBRARY_PATH
+ ? `:${process.env.LD_LIBRARY_PATH}`
+ : '';
+ const pyLibPath = path.join(installDir, 'lib');
- const userScriptsDir = path.join(
- process.env['APPDATA'] || '',
- 'Python',
- `Python${major}${minor}`,
- 'Scripts'
- );
- core.addPath(userScriptsDir);
+ if (!libPath.split(':').includes(pyLibPath)) {
+ core.exportVariable('LD_LIBRARY_PATH', pyLibPath + libPath);
+ }
+ }
+ core.addPath(installDir);
+ core.addPath(_binDir);
+
+ if (IS_WINDOWS) {
+ // Add --user directory
+ // `installDir` from tool cache should look like $RUNNER_TOOL_CACHE/Python//x64/
+ // So if `findLocalTool` succeeded above, we must have a conformant `installDir`
+ const version = path.basename(path.dirname(installDir));
+ const major = semver.major(version);
+ const minor = semver.minor(version);
+
+ const userScriptsDir = path.join(
+ process.env['APPDATA'] || '',
+ 'Python',
+ `Python${major}${minor}`,
+ 'Scripts'
+ );
+ core.addPath(userScriptsDir);
+ }
+ // On Linux and macOS, pip will create the --user directory and add it to PATH as needed.
}
- // On Linux and macOS, pip will create the --user directory and add it to PATH as needed.
const installed = versionFromPath(installDir);
core.setOutput('python-version', installed);
diff --git a/src/setup-python.ts b/src/setup-python.ts
index 2ffeb1ad..a7728714 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -64,14 +64,23 @@ async function run() {
if (version) {
let pythonVersion: string;
const arch: string = core.getInput('architecture') || os.arch();
+ const updateEnvironment = core.getBooleanInput('update-environment');
if (isPyPyVersion(version)) {
- const installed = await finderPyPy.findPyPyVersion(version, arch);
+ const installed = await finderPyPy.findPyPyVersion(
+ version,
+ arch,
+ updateEnvironment
+ );
pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`;
core.info(
`Successfully set up PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})`
);
} else {
- const installed = await finder.useCpythonVersion(version, arch);
+ const installed = await finder.useCpythonVersion(
+ version,
+ arch,
+ updateEnvironment
+ );
pythonVersion = installed.version;
core.info(`Successfully set up ${installed.impl} (${pythonVersion})`);
}
From 766e8c60885ef280a3e447209d1f1083b3c7039d Mon Sep 17 00:00:00 2001
From: Dmitry Shibanov
Date: Wed, 29 Jun 2022 19:09:14 +0200
Subject: [PATCH 10/77] Fixing pipenv CI (#444)
* work on fixing pipenv
* change installation of pipenv to curl
* add different logs
* regenerate pipefile.lock
* change pipenv ci
---
.github/workflows/e2e-cache.yml | 14 ++--
README.md | 8 +--
__tests__/cache-restore.test.ts | 2 +-
__tests__/data/Pipfile | 4 +-
__tests__/data/Pipfile.lock | 115 ++++++++++++++------------------
5 files changed, 64 insertions(+), 79 deletions(-)
diff --git a/.github/workflows/e2e-cache.yml b/.github/workflows/e2e-cache.yml
index ce3366a1..d28fa2c0 100644
--- a/.github/workflows/e2e-cache.yml
+++ b/.github/workflows/e2e-cache.yml
@@ -48,11 +48,12 @@ jobs:
python-version: ${{ matrix.python-version }}
cache: 'pipenv'
- name: Install pipenv
- run: pipx install pipenv
+ run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python
- name: Install dependencies
run: |
- cd __tests__/data
- pipenv install --verbose
+ mv ./__tests__/data/Pipfile.lock .
+ mv ./__tests__/data/Pipfile .
+ pipenv install --keep-outdated
python-poetry-dependencies-caching:
name: Test poetry (Python ${{ matrix.python-version}}, ${{ matrix.os }})
@@ -112,8 +113,9 @@ jobs:
cache: 'pipenv'
cache-dependency-path: '**/pipenv-requirements.txt'
- name: Install pipenv
- run: pipx install pipenv
+ run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python
- name: Install dependencies
run: |
- cd __tests__/data
- pipenv install --verbose
\ No newline at end of file
+ mv ./__tests__/data/Pipfile.lock .
+ mv ./__tests__/data/Pipfile .
+ pipenv install --keep-outdated
\ No newline at end of file
diff --git a/README.md b/README.md
index 5adb2033..84b2e642 100644
--- a/README.md
+++ b/README.md
@@ -269,12 +269,12 @@ steps:
```yaml
steps:
- uses: actions/checkout@v3
-- name: Install pipenv
- run: pipx install pipenv
- uses: actions/setup-python@v4
with:
python-version: '3.9'
cache: 'pipenv'
+- name: Install pipenv
+ run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python
- run: pipenv install
```
@@ -308,8 +308,6 @@ steps:
```yaml
steps:
- uses: actions/checkout@v3
-- name: Install pipenv
- run: pipx install pipenv
- uses: actions/setup-python@v4
with:
python-version: '3.9'
@@ -317,6 +315,8 @@ steps:
cache-dependency-path: |
server/app/Pipfile.lock
__test__/app/Pipfile.lock
+- name: Install pipenv
+ run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python
- run: pipenv install
```
diff --git a/__tests__/cache-restore.test.ts b/__tests__/cache-restore.test.ts
index 99b674ef..573f36a9 100644
--- a/__tests__/cache-restore.test.ts
+++ b/__tests__/cache-restore.test.ts
@@ -5,7 +5,7 @@ import {getCacheDistributor} from '../src/cache-distributions/cache-factory';
describe('restore-cache', () => {
const pipFileLockHash =
- 'd1dd6218299d8a6db5fc2001d988b34a8b31f1e9d0bb4534d377dde7c19f64b3';
+ 'a3bdcc71289e4979ca9e051810d81999cc99823109faf6912e17ff14c8e621a6';
const requirementsHash =
'd8110e0006d7fb5ee76365d565eef9d37df1d11598b912d3eb66d398d57a1121';
const requirementsLinuxHash =
diff --git a/__tests__/data/Pipfile b/__tests__/data/Pipfile
index 8208ab35..8db54551 100644
--- a/__tests__/data/Pipfile
+++ b/__tests__/data/Pipfile
@@ -4,8 +4,8 @@ verify_ssl = true
name = "pypi"
[packages]
-numpy = "1.22.3"
-pandas = "1.4.2"
+flake8 = "==4.0.1"
+numpy = "==1.23.0"
[dev-packages]
diff --git a/__tests__/data/Pipfile.lock b/__tests__/data/Pipfile.lock
index 5a67a8fc..9fcecefb 100644
--- a/__tests__/data/Pipfile.lock
+++ b/__tests__/data/Pipfile.lock
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
- "sha256": "33e3640eff8b2b6c7149b85568151f39a66c544033b4b3f3f2ec9ad5ce6dfe7e"
+ "sha256": "e9c37110984955621040e2dc8548c026eb8466c23db1b8e69430289b10be8938"
},
"pipfile-spec": 6,
"requires": {
@@ -16,81 +16,64 @@
]
},
"default": {
+ "flake8": {
+ "hashes": [
+ "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d",
+ "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"
+ ],
+ "index": "pypi",
+ "version": "==4.0.1"
+ },
+ "mccabe": {
+ "hashes": [
+ "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
+ "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
+ ],
+ "version": "==0.6.1"
+ },
"numpy": {
"hashes": [
- "sha256:07a8c89a04997625236c5ecb7afe35a02af3896c8aa01890a849913a2309c676",
- "sha256:08d9b008d0156c70dc392bb3ab3abb6e7a711383c3247b410b39962263576cd4",
- "sha256:201b4d0552831f7250a08d3b38de0d989d6f6e4658b709a02a73c524ccc6ffce",
- "sha256:2c10a93606e0b4b95c9b04b77dc349b398fdfbda382d2a39ba5a822f669a0123",
- "sha256:3ca688e1b9b95d80250bca34b11a05e389b1420d00e87a0d12dc45f131f704a1",
- "sha256:48a3aecd3b997bf452a2dedb11f4e79bc5bfd21a1d4cc760e703c31d57c84b3e",
- "sha256:568dfd16224abddafb1cbcce2ff14f522abe037268514dd7e42c6776a1c3f8e5",
- "sha256:5bfb1bb598e8229c2d5d48db1860bcf4311337864ea3efdbe1171fb0c5da515d",
- "sha256:639b54cdf6aa4f82fe37ebf70401bbb74b8508fddcf4797f9fe59615b8c5813a",
- "sha256:8251ed96f38b47b4295b1ae51631de7ffa8260b5b087808ef09a39a9d66c97ab",
- "sha256:92bfa69cfbdf7dfc3040978ad09a48091143cffb778ec3b03fa170c494118d75",
- "sha256:97098b95aa4e418529099c26558eeb8486e66bd1e53a6b606d684d0c3616b168",
- "sha256:a3bae1a2ed00e90b3ba5f7bd0a7c7999b55d609e0c54ceb2b076a25e345fa9f4",
- "sha256:c34ea7e9d13a70bf2ab64a2532fe149a9aced424cd05a2c4ba662fd989e3e45f",
- "sha256:dbc7601a3b7472d559dc7b933b18b4b66f9aa7452c120e87dfb33d02008c8a18",
- "sha256:e7927a589df200c5e23c57970bafbd0cd322459aa7b1ff73b7c2e84d6e3eae62",
- "sha256:f8c1f39caad2c896bc0018f699882b345b2a63708008be29b1f355ebf6f933fe",
- "sha256:f950f8845b480cffe522913d35567e29dd381b0dc7e4ce6a4a9f9156417d2430",
- "sha256:fade0d4f4d292b6f39951b6836d7a3c7ef5b2347f3c420cd9820a1d90d794802",
- "sha256:fdf3c08bce27132395d3c3ba1503cac12e17282358cb4bddc25cc46b0aca07aa"
+ "sha256:092f5e6025813e64ad6d1b52b519165d08c730d099c114a9247c9bb635a2a450",
+ "sha256:196cd074c3f97c4121601790955f915187736f9cf458d3ee1f1b46aff2b1ade0",
+ "sha256:1c29b44905af288b3919803aceb6ec7fec77406d8b08aaa2e8b9e63d0fe2f160",
+ "sha256:2b2da66582f3a69c8ce25ed7921dcd8010d05e59ac8d89d126a299be60421171",
+ "sha256:5043bcd71fcc458dfb8a0fc5509bbc979da0131b9d08e3d5f50fb0bbb36f169a",
+ "sha256:58bfd40eb478f54ff7a5710dd61c8097e169bc36cc68333d00a9bcd8def53b38",
+ "sha256:79a506cacf2be3a74ead5467aee97b81fca00c9c4c8b3ba16dbab488cd99ba10",
+ "sha256:94b170b4fa0168cd6be4becf37cb5b127bd12a795123984385b8cd4aca9857e5",
+ "sha256:97a76604d9b0e79f59baeca16593c711fddb44936e40310f78bfef79ee9a835f",
+ "sha256:98e8e0d8d69ff4d3fa63e6c61e8cfe2d03c29b16b58dbef1f9baa175bbed7860",
+ "sha256:ac86f407873b952679f5f9e6c0612687e51547af0e14ddea1eedfcb22466babd",
+ "sha256:ae8adff4172692ce56233db04b7ce5792186f179c415c37d539c25de7298d25d",
+ "sha256:bd3fa4fe2e38533d5336e1272fc4e765cabbbde144309ccee8675509d5cd7b05",
+ "sha256:d0d2094e8f4d760500394d77b383a1b06d3663e8892cdf5df3c592f55f3bff66",
+ "sha256:d54b3b828d618a19779a84c3ad952e96e2c2311b16384e973e671aa5be1f6187",
+ "sha256:d6ca8dabe696c2785d0c8c9b0d8a9b6e5fdbe4f922bde70d57fa1a2848134f95",
+ "sha256:d8cc87bed09de55477dba9da370c1679bd534df9baa171dd01accbb09687dac3",
+ "sha256:f0f18804df7370571fb65db9b98bf1378172bd4e962482b857e612d1fec0f53e",
+ "sha256:f1d88ef79e0a7fa631bb2c3dda1ea46b32b1fe614e10fedd611d3d5398447f2f",
+ "sha256:f9c3fc2adf67762c9fe1849c859942d23f8d3e0bee7b5ed3d4a9c3eeb50a2f07",
+ "sha256:fc431493df245f3c627c0c05c2bd134535e7929dbe2e602b80e42bf52ff760bc",
+ "sha256:fe8b9683eb26d2c4d5db32cd29b38fdcf8381324ab48313b5b69088e0e355379"
],
"index": "pypi",
- "version": "==1.22.3"
+ "version": "==1.23.0"
},
- "pandas": {
+ "pycodestyle": {
"hashes": [
- "sha256:0010771bd9223f7afe5f051eb47c4a49534345dfa144f2f5470b27189a4dd3b5",
- "sha256:061609334a8182ab500a90fe66d46f6f387de62d3a9cb9aa7e62e3146c712167",
- "sha256:09d8be7dd9e1c4c98224c4dfe8abd60d145d934e9fc1f5f411266308ae683e6a",
- "sha256:295872bf1a09758aba199992c3ecde455f01caf32266d50abc1a073e828a7b9d",
- "sha256:3228198333dd13c90b6434ddf61aa6d57deaca98cf7b654f4ad68a2db84f8cfe",
- "sha256:385c52e85aaa8ea6a4c600a9b2821181a51f8be0aee3af6f2dcb41dafc4fc1d0",
- "sha256:51649ef604a945f781105a6d2ecf88db7da0f4868ac5d45c51cb66081c4d9c73",
- "sha256:5586cc95692564b441f4747c47c8a9746792e87b40a4680a2feb7794defb1ce3",
- "sha256:5a206afa84ed20e07603f50d22b5f0db3fb556486d8c2462d8bc364831a4b417",
- "sha256:5b79af3a69e5175c6fa7b4e046b21a646c8b74e92c6581a9d825687d92071b51",
- "sha256:5c54ea4ef3823108cd4ec7fb27ccba4c3a775e0f83e39c5e17f5094cb17748bc",
- "sha256:8c5bf555b6b0075294b73965adaafb39cf71c312e38c5935c93d78f41c19828a",
- "sha256:92bc1fc585f1463ca827b45535957815b7deb218c549b7c18402c322c7549a12",
- "sha256:95c1e422ced0199cf4a34385ff124b69412c4bc912011ce895582bee620dfcaa",
- "sha256:b8134651258bce418cb79c71adeff0a44090c98d955f6953168ba16cc285d9f7",
- "sha256:be67c782c4f1b1f24c2f16a157e12c2693fd510f8df18e3287c77f33d124ed07",
- "sha256:c072c7f06b9242c855ed8021ff970c0e8f8b10b35e2640c657d2a541c5950f59",
- "sha256:d0d4f13e4be7ce89d7057a786023c461dd9370040bdb5efa0a7fe76b556867a0",
- "sha256:df82739e00bb6daf4bba4479a40f38c718b598a84654cbd8bb498fd6b0aa8c16",
- "sha256:f549097993744ff8c41b5e8f2f0d3cbfaabe89b4ae32c8c08ead6cc535b80139",
- "sha256:ff08a14ef21d94cdf18eef7c569d66f2e24e0bc89350bcd7d243dd804e3b5eb2"
+ "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20",
+ "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"
],
- "index": "pypi",
- "version": "==1.4.2"
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
+ "version": "==2.8.0"
},
- "python-dateutil": {
+ "pyflakes": {
"hashes": [
- "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86",
- "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"
+ "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c",
+ "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
- "version": "==2.8.2"
- },
- "pytz": {
- "hashes": [
- "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7",
- "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"
- ],
- "version": "==2022.1"
- },
- "six": {
- "hashes": [
- "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
- "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
- "version": "==1.16.0"
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+ "version": "==2.4.0"
}
},
"develop": {}
From 2a20d9b5e033c63a77fbb5fa1074a8a9192bbd68 Mon Sep 17 00:00:00 2001
From: Dmitry Shibanov
Date: Wed, 29 Jun 2022 19:36:35 +0200
Subject: [PATCH 11/77] add --python 3
---
.github/workflows/e2e-cache.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/e2e-cache.yml b/.github/workflows/e2e-cache.yml
index d28fa2c0..ba0f4e40 100644
--- a/.github/workflows/e2e-cache.yml
+++ b/.github/workflows/e2e-cache.yml
@@ -53,7 +53,7 @@ jobs:
run: |
mv ./__tests__/data/Pipfile.lock .
mv ./__tests__/data/Pipfile .
- pipenv install --keep-outdated
+ pipenv install --keep-outdated --python 3
python-poetry-dependencies-caching:
name: Test poetry (Python ${{ matrix.python-version}}, ${{ matrix.os }})
@@ -118,4 +118,4 @@ jobs:
run: |
mv ./__tests__/data/Pipfile.lock .
mv ./__tests__/data/Pipfile .
- pipenv install --keep-outdated
\ No newline at end of file
+ pipenv install --keep-outdated --python 3
\ No newline at end of file
From 1e52de40a4a5827eaf838418993a2c92338dd220 Mon Sep 17 00:00:00 2001
From: Dmitry Shibanov
Date: Wed, 29 Jun 2022 20:16:07 +0200
Subject: [PATCH 12/77] fixing pipenv
---
.github/workflows/e2e-cache.yml | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/e2e-cache.yml b/.github/workflows/e2e-cache.yml
index ba0f4e40..05400978 100644
--- a/.github/workflows/e2e-cache.yml
+++ b/.github/workflows/e2e-cache.yml
@@ -50,10 +50,15 @@ jobs:
- name: Install pipenv
run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python
- name: Install dependencies
+ shell: pwsh
run: |
mv ./__tests__/data/Pipfile.lock .
mv ./__tests__/data/Pipfile .
- pipenv install --keep-outdated --python 3
+ if (${{ matrix.python-version }} -Match "pypy") {
+ pipenv install --keep-outdated --python ${{ matrix.python-version }}
+ } else {
+ pipenv install --keep-outdated --python pypy
+ }
python-poetry-dependencies-caching:
name: Test poetry (Python ${{ matrix.python-version}}, ${{ matrix.os }})
@@ -115,7 +120,12 @@ jobs:
- name: Install pipenv
run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python
- name: Install dependencies
+ shell: pwsh
run: |
mv ./__tests__/data/Pipfile.lock .
mv ./__tests__/data/Pipfile .
- pipenv install --keep-outdated --python 3
\ No newline at end of file
+ if (${{ matrix.python-version }} -Match "pypy") {
+ pipenv install --keep-outdated --python ${{ matrix.python-version }}
+ } else {
+ pipenv install --keep-outdated --python pypy
+ }
\ No newline at end of file
From d358f9e3d736263647a0848999f287bf1f66d499 Mon Sep 17 00:00:00 2001
From: Dmitry Shibanov
Date: Wed, 29 Jun 2022 20:28:20 +0200
Subject: [PATCH 13/77] fix check
---
.github/workflows/e2e-cache.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/e2e-cache.yml b/.github/workflows/e2e-cache.yml
index 05400978..c580dca8 100644
--- a/.github/workflows/e2e-cache.yml
+++ b/.github/workflows/e2e-cache.yml
@@ -54,7 +54,7 @@ jobs:
run: |
mv ./__tests__/data/Pipfile.lock .
mv ./__tests__/data/Pipfile .
- if (${{ matrix.python-version }} -Match "pypy") {
+ if ("${{ matrix.python-version }}" -Match "pypy") {
pipenv install --keep-outdated --python ${{ matrix.python-version }}
} else {
pipenv install --keep-outdated --python pypy
@@ -124,7 +124,7 @@ jobs:
run: |
mv ./__tests__/data/Pipfile.lock .
mv ./__tests__/data/Pipfile .
- if (${{ matrix.python-version }} -Match "pypy") {
+ if ("${{ matrix.python-version }}" -Match "pypy") {
pipenv install --keep-outdated --python ${{ matrix.python-version }}
} else {
pipenv install --keep-outdated --python pypy
From 27091d50ca103a5c3ae2c53c07881b7b7e5b95b9 Mon Sep 17 00:00:00 2001
From: Dmitry Shibanov
Date: Wed, 29 Jun 2022 20:38:02 +0200
Subject: [PATCH 14/77] minor fix
---
.github/workflows/e2e-cache.yml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/e2e-cache.yml b/.github/workflows/e2e-cache.yml
index c580dca8..a0977007 100644
--- a/.github/workflows/e2e-cache.yml
+++ b/.github/workflows/e2e-cache.yml
@@ -55,9 +55,9 @@ jobs:
mv ./__tests__/data/Pipfile.lock .
mv ./__tests__/data/Pipfile .
if ("${{ matrix.python-version }}" -Match "pypy") {
- pipenv install --keep-outdated --python ${{ matrix.python-version }}
- } else {
pipenv install --keep-outdated --python pypy
+ } else {
+ pipenv install --keep-outdated --python ${{ matrix.python-version }}
}
python-poetry-dependencies-caching:
@@ -125,7 +125,7 @@ jobs:
mv ./__tests__/data/Pipfile.lock .
mv ./__tests__/data/Pipfile .
if ("${{ matrix.python-version }}" -Match "pypy") {
- pipenv install --keep-outdated --python ${{ matrix.python-version }}
- } else {
pipenv install --keep-outdated --python pypy
+ } else {
+ pipenv install --keep-outdated --python ${{ matrix.python-version }}
}
\ No newline at end of file
From d7db8259d9728b6b49900079b1472482cd2ad053 Mon Sep 17 00:00:00 2001
From: Dmitry Shibanov
Date: Wed, 29 Jun 2022 23:41:39 +0200
Subject: [PATCH 15/77] update pypy versions
---
.github/workflows/e2e-cache.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/e2e-cache.yml b/.github/workflows/e2e-cache.yml
index a0977007..0aea4b77 100644
--- a/.github/workflows/e2e-cache.yml
+++ b/.github/workflows/e2e-cache.yml
@@ -39,7 +39,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
- python-version: ['3.9', 'pypy-3.7-v7.x']
+ python-version: ['3.9', 'pypy-3.9-v7.x']
steps:
- uses: actions/checkout@v3
- name: Setup Python
@@ -108,7 +108,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
- python-version: ['3.9', 'pypy-3.7-v7.x']
+ python-version: ['3.9', 'pypy-3.9-v7.x']
steps:
- uses: actions/checkout@v3
- name: Setup Python
From 69b94463f514b2e3874657553880d9cd8693e693 Mon Sep 17 00:00:00 2001
From: Sergey Dolin
Date: Tue, 28 Jun 2022 08:37:00 +0200
Subject: [PATCH 16/77] Add CMake hints
---
dist/setup/index.js | 33 +++++++++++++++++++++++++++++++++
src/find-pypy.ts | 6 ++++++
src/find-python.ts | 20 ++++++++++++++++++++
3 files changed, 59 insertions(+)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index cdd0f706..382db122 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -63884,12 +63884,25 @@ function findPyPyVersion(versionSpec, architecture, updateEnvironment) {
const binaryExtension = utils_1.IS_WINDOWS ? '.exe' : '';
const pythonPath = path.join(utils_1.IS_WINDOWS ? installDir : _binDir, `python${binaryExtension}`);
const pythonLocation = pypyInstall.getPyPyBinaryPath(installDir);
+<<<<<<< HEAD
if (updateEnvironment) {
core.exportVariable('pythonLocation', installDir);
core.exportVariable('PKG_CONFIG_PATH', pythonLocation + '/lib/pkgconfig');
core.addPath(pythonLocation);
core.addPath(_binDir);
}
+=======
+ core.exportVariable('pythonLocation', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython
+ core.exportVariable('Python_ROOT_DIR', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython2
+ core.exportVariable('Python2_ROOT_DIR', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython3.html#module:FindPython3
+ core.exportVariable('Python3_ROOT_DIR', installDir);
+ core.exportVariable('PKG_CONFIG_PATH', pythonLocation + '/lib/pkgconfig');
+ core.addPath(pythonLocation);
+ core.addPath(_binDir);
+>>>>>>> 31fd3d4 (Add CMake hints)
core.setOutput('python-version', 'pypy' + resolvedPyPyVersion.trim());
core.setOutput('python-path', pythonPath);
return { resolvedPyPyVersion, resolvedPythonVersion };
@@ -64042,6 +64055,26 @@ function useCpythonVersion(version, architecture, updateEnvironment) {
`The list of all available versions can be found here: ${installer.MANIFEST_URL}`
].join(os.EOL));
}
+<<<<<<< HEAD
+=======
+ core.exportVariable('pythonLocation', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython
+ core.exportVariable('Python_ROOT_DIR', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython2
+ core.exportVariable('Python2_ROOT_DIR', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython3.html#module:FindPython3
+ core.exportVariable('Python3_ROOT_DIR', installDir);
+ core.exportVariable('PKG_CONFIG_PATH', installDir + '/lib/pkgconfig');
+ if (utils_1.IS_LINUX) {
+ const libPath = process.env.LD_LIBRARY_PATH
+ ? `:${process.env.LD_LIBRARY_PATH}`
+ : '';
+ const pyLibPath = path.join(installDir, 'lib');
+ if (!libPath.split(':').includes(pyLibPath)) {
+ core.exportVariable('LD_LIBRARY_PATH', pyLibPath + libPath);
+ }
+ }
+>>>>>>> 31fd3d4 (Add CMake hints)
const _binDir = binDir(installDir);
const binaryExtension = utils_1.IS_WINDOWS ? '.exe' : '';
const pythonPath = path.join(utils_1.IS_WINDOWS ? installDir : _binDir, `python${binaryExtension}`);
diff --git a/src/find-pypy.ts b/src/find-pypy.ts
index a1949629..3cc3fdd2 100644
--- a/src/find-pypy.ts
+++ b/src/find-pypy.ts
@@ -57,6 +57,12 @@ export async function findPyPyVersion(
const pythonLocation = pypyInstall.getPyPyBinaryPath(installDir);
if (updateEnvironment) {
core.exportVariable('pythonLocation', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython
+ core.exportVariable('Python_ROOT_DIR', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython2
+ core.exportVariable('Python2_ROOT_DIR', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython3.html#module:FindPython3
+ core.exportVariable('Python3_ROOT_DIR', installDir);
core.exportVariable('PKG_CONFIG_PATH', pythonLocation + '/lib/pkgconfig');
core.addPath(pythonLocation);
core.addPath(_binDir);
diff --git a/src/find-python.ts b/src/find-python.ts
index 96759606..339c615d 100644
--- a/src/find-python.ts
+++ b/src/find-python.ts
@@ -70,6 +70,26 @@ export async function useCpythonVersion(
);
}
+ core.exportVariable('pythonLocation', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython
+ core.exportVariable('Python_ROOT_DIR', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython2
+ core.exportVariable('Python2_ROOT_DIR', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython3.html#module:FindPython3
+ core.exportVariable('Python3_ROOT_DIR', installDir);
+ core.exportVariable('PKG_CONFIG_PATH', installDir + '/lib/pkgconfig');
+
+ if (IS_LINUX) {
+ const libPath = process.env.LD_LIBRARY_PATH
+ ? `:${process.env.LD_LIBRARY_PATH}`
+ : '';
+ const pyLibPath = path.join(installDir, 'lib');
+
+ if (!libPath.split(':').includes(pyLibPath)) {
+ core.exportVariable('LD_LIBRARY_PATH', pyLibPath + libPath);
+ }
+ }
+
const _binDir = binDir(installDir);
const binaryExtension = IS_WINDOWS ? '.exe' : '';
const pythonPath = path.join(
From 63086c6dedb585bdcbe92068dcf2e8229aadda5d Mon Sep 17 00:00:00 2001
From: Sergey Dolin
Date: Thu, 30 Jun 2022 07:46:53 +0200
Subject: [PATCH 17/77] rebase main
---
dist/setup/index.js | 22 ++++++----------------
1 file changed, 6 insertions(+), 16 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 382db122..a6c62eca 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -63884,25 +63884,18 @@ function findPyPyVersion(versionSpec, architecture, updateEnvironment) {
const binaryExtension = utils_1.IS_WINDOWS ? '.exe' : '';
const pythonPath = path.join(utils_1.IS_WINDOWS ? installDir : _binDir, `python${binaryExtension}`);
const pythonLocation = pypyInstall.getPyPyBinaryPath(installDir);
-<<<<<<< HEAD
if (updateEnvironment) {
core.exportVariable('pythonLocation', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython
+ core.exportVariable('Python_ROOT_DIR', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython2
+ core.exportVariable('Python2_ROOT_DIR', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython3.html#module:FindPython3
+ core.exportVariable('Python3_ROOT_DIR', installDir);
core.exportVariable('PKG_CONFIG_PATH', pythonLocation + '/lib/pkgconfig');
core.addPath(pythonLocation);
core.addPath(_binDir);
}
-=======
- core.exportVariable('pythonLocation', installDir);
- // https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython
- core.exportVariable('Python_ROOT_DIR', installDir);
- // https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython2
- core.exportVariable('Python2_ROOT_DIR', installDir);
- // https://cmake.org/cmake/help/latest/module/FindPython3.html#module:FindPython3
- core.exportVariable('Python3_ROOT_DIR', installDir);
- core.exportVariable('PKG_CONFIG_PATH', pythonLocation + '/lib/pkgconfig');
- core.addPath(pythonLocation);
- core.addPath(_binDir);
->>>>>>> 31fd3d4 (Add CMake hints)
core.setOutput('python-version', 'pypy' + resolvedPyPyVersion.trim());
core.setOutput('python-path', pythonPath);
return { resolvedPyPyVersion, resolvedPythonVersion };
@@ -64055,8 +64048,6 @@ function useCpythonVersion(version, architecture, updateEnvironment) {
`The list of all available versions can be found here: ${installer.MANIFEST_URL}`
].join(os.EOL));
}
-<<<<<<< HEAD
-=======
core.exportVariable('pythonLocation', installDir);
// https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython
core.exportVariable('Python_ROOT_DIR', installDir);
@@ -64074,7 +64065,6 @@ function useCpythonVersion(version, architecture, updateEnvironment) {
core.exportVariable('LD_LIBRARY_PATH', pyLibPath + libPath);
}
}
->>>>>>> 31fd3d4 (Add CMake hints)
const _binDir = binDir(installDir);
const binaryExtension = utils_1.IS_WINDOWS ? '.exe' : '';
const pythonPath = path.join(utils_1.IS_WINDOWS ? installDir : _binDir, `python${binaryExtension}`);
From e629242ad48d47433d193493ea6cfb63b06c58e3 Mon Sep 17 00:00:00 2001
From: Sergey Dolin
Date: Thu, 30 Jun 2022 07:56:08 +0200
Subject: [PATCH 18/77] Fix failed check
---
dist/setup/index.js | 16 ++++++++--------
src/find-python.ts | 17 ++++++++---------
2 files changed, 16 insertions(+), 17 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index a6c62eca..b98b9af2 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -64048,14 +64048,6 @@ function useCpythonVersion(version, architecture, updateEnvironment) {
`The list of all available versions can be found here: ${installer.MANIFEST_URL}`
].join(os.EOL));
}
- core.exportVariable('pythonLocation', installDir);
- // https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython
- core.exportVariable('Python_ROOT_DIR', installDir);
- // https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython2
- core.exportVariable('Python2_ROOT_DIR', installDir);
- // https://cmake.org/cmake/help/latest/module/FindPython3.html#module:FindPython3
- core.exportVariable('Python3_ROOT_DIR', installDir);
- core.exportVariable('PKG_CONFIG_PATH', installDir + '/lib/pkgconfig');
if (utils_1.IS_LINUX) {
const libPath = process.env.LD_LIBRARY_PATH
? `:${process.env.LD_LIBRARY_PATH}`
@@ -64071,6 +64063,14 @@ function useCpythonVersion(version, architecture, updateEnvironment) {
if (updateEnvironment) {
core.exportVariable('pythonLocation', installDir);
core.exportVariable('PKG_CONFIG_PATH', installDir + '/lib/pkgconfig');
+ core.exportVariable('pythonLocation', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython
+ core.exportVariable('Python_ROOT_DIR', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython2
+ core.exportVariable('Python2_ROOT_DIR', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython3.html#module:FindPython3
+ core.exportVariable('Python3_ROOT_DIR', installDir);
+ core.exportVariable('PKG_CONFIG_PATH', installDir + '/lib/pkgconfig');
if (utils_1.IS_LINUX) {
const libPath = process.env.LD_LIBRARY_PATH
? `:${process.env.LD_LIBRARY_PATH}`
diff --git a/src/find-python.ts b/src/find-python.ts
index 339c615d..8c085d61 100644
--- a/src/find-python.ts
+++ b/src/find-python.ts
@@ -70,15 +70,6 @@ export async function useCpythonVersion(
);
}
- core.exportVariable('pythonLocation', installDir);
- // https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython
- core.exportVariable('Python_ROOT_DIR', installDir);
- // https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython2
- core.exportVariable('Python2_ROOT_DIR', installDir);
- // https://cmake.org/cmake/help/latest/module/FindPython3.html#module:FindPython3
- core.exportVariable('Python3_ROOT_DIR', installDir);
- core.exportVariable('PKG_CONFIG_PATH', installDir + '/lib/pkgconfig');
-
if (IS_LINUX) {
const libPath = process.env.LD_LIBRARY_PATH
? `:${process.env.LD_LIBRARY_PATH}`
@@ -99,6 +90,14 @@ export async function useCpythonVersion(
if (updateEnvironment) {
core.exportVariable('pythonLocation', installDir);
core.exportVariable('PKG_CONFIG_PATH', installDir + '/lib/pkgconfig');
+ core.exportVariable('pythonLocation', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython
+ core.exportVariable('Python_ROOT_DIR', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython2
+ core.exportVariable('Python2_ROOT_DIR', installDir);
+ // https://cmake.org/cmake/help/latest/module/FindPython3.html#module:FindPython3
+ core.exportVariable('Python3_ROOT_DIR', installDir);
+ core.exportVariable('PKG_CONFIG_PATH', installDir + '/lib/pkgconfig');
if (IS_LINUX) {
const libPath = process.env.LD_LIBRARY_PATH
From afd3e72a25e35f57d63421163b2bfa536eded186 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Thu, 30 Jun 2022 13:38:43 +0200
Subject: [PATCH 19/77] Fix bug in resolveVersionInput()
---
dist/setup/index.js | 22 +++++++++++++++++-----
src/setup-python.ts | 32 ++++++++++++++++++++++++--------
2 files changed, 41 insertions(+), 13 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index b98b9af2..e7cfc7a1 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -64471,12 +64471,24 @@ function resolveVersionInput() {
if (version) {
return version;
}
- versionFile = versionFile || '.python-version';
- if (!fs_1.default.existsSync(versionFile)) {
- throw new Error(`The specified python version file at: ${versionFile} does not exist`);
+ if (versionFile) {
+ const defaultVersionFile = '.python-version';
+ const VersionFileExists = fs_1.default.existsSync(versionFile);
+ const defaultVersionFileExists = fs_1.default.existsSync(defaultVersionFile);
+ if (!VersionFileExists && !defaultVersionFileExists) {
+ throw new Error(`The specified python version file at: ${versionFile} does not exist and default ${defaultVersionFile} file isn't found`);
+ }
+ if (VersionFileExists) {
+ version = fs_1.default.readFileSync(versionFile, 'utf8');
+ core.info(`Resolved ${versionFile} as ${version}`);
+ }
+ else {
+ version = fs_1.default.readFileSync('.python-version', 'utf8');
+ core.info(`Resolved ${'.python-version'} as ${version}`);
+ }
+ return version;
}
- version = fs_1.default.readFileSync(versionFile, 'utf8');
- core.info(`Resolved ${versionFile} as ${version}`);
+ core.warning("Neither 'python-version' nor 'python-version-file' inputs were supplied. ");
return version;
}
function run() {
diff --git a/src/setup-python.ts b/src/setup-python.ts
index a7728714..97efe538 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -36,15 +36,31 @@ function resolveVersionInput(): string {
return version;
}
- versionFile = versionFile || '.python-version';
- if (!fs.existsSync(versionFile)) {
- throw new Error(
- `The specified python version file at: ${versionFile} does not exist`
- );
- }
- version = fs.readFileSync(versionFile, 'utf8');
- core.info(`Resolved ${versionFile} as ${version}`);
+ if (versionFile) {
+ const defaultVersionFile = '.python-version';
+ const VersionFileExists = fs.existsSync(versionFile);
+ const defaultVersionFileExists = fs.existsSync(defaultVersionFile);
+
+ if (!VersionFileExists && !defaultVersionFileExists) {
+ throw new Error(
+ `The specified python version file at: ${versionFile} does not exist and default ${defaultVersionFile} file isn't found`
+ );
+ }
+ if (VersionFileExists) {
+ version = fs.readFileSync(versionFile, 'utf8');
+ core.info(`Resolved ${versionFile} as ${version}`);
+ } else {
+ version = fs.readFileSync('.python-version', 'utf8');
+ core.info(`Resolved ${'.python-version'} as ${version}`);
+ }
+
+ return version;
+ }
+
+ core.warning(
+ "Neither 'python-version' nor 'python-version-file' inputs were supplied. "
+ );
return version;
}
From 6733fc44ecfb2ab941c4b659afcfb87d2836391d Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Thu, 30 Jun 2022 13:44:10 +0200
Subject: [PATCH 20/77] Fix typo
---
dist/setup/index.js | 4 ++--
src/setup-python.ts | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index e7cfc7a1..9ca5fb7c 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -64483,8 +64483,8 @@ function resolveVersionInput() {
core.info(`Resolved ${versionFile} as ${version}`);
}
else {
- version = fs_1.default.readFileSync('.python-version', 'utf8');
- core.info(`Resolved ${'.python-version'} as ${version}`);
+ version = fs_1.default.readFileSync(defaultVersionFile, 'utf8');
+ core.info(`Resolved ${defaultVersionFile} as ${version}`);
}
return version;
}
diff --git a/src/setup-python.ts b/src/setup-python.ts
index 97efe538..58ebd8d0 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -51,8 +51,8 @@ function resolveVersionInput(): string {
version = fs.readFileSync(versionFile, 'utf8');
core.info(`Resolved ${versionFile} as ${version}`);
} else {
- version = fs.readFileSync('.python-version', 'utf8');
- core.info(`Resolved ${'.python-version'} as ${version}`);
+ version = fs.readFileSync(defaultVersionFile, 'utf8');
+ core.info(`Resolved ${defaultVersionFile} as ${version}`);
}
return version;
From 08116500d0db25c48998f7ec763d4a6ac7d1f3d7 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Thu, 30 Jun 2022 14:19:36 +0200
Subject: [PATCH 21/77] Rebuild action
---
dist/cache-save/index.js | 827 +--------------------------------------
dist/setup/index.js | 61 +--
2 files changed, 31 insertions(+), 857 deletions(-)
diff --git a/dist/cache-save/index.js b/dist/cache-save/index.js
index 0aeb47e7..8ede282a 100644
--- a/dist/cache-save/index.js
+++ b/dist/cache-save/index.js
@@ -90,18 +90,17 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
checkKey(key);
}
const compressionMethod = yield utils.getCompressionMethod();
- let archivePath = '';
+ // path are needed to compute version
+ const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
+ compressionMethod
+ });
+ if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
+ // Cache not found
+ return undefined;
+ }
+ const archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
+ core.debug(`Archive Path: ${archivePath}`);
try {
- // path are needed to compute version
- const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
- compressionMethod
- });
- if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
- // Cache not found
- return undefined;
- }
- archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
- core.debug(`Archive Path: ${archivePath}`);
// Download the cache from the cache entry
yield cacheHttpClient.downloadCache(cacheEntry.archiveLocation, archivePath, options);
if (core.isDebug()) {
@@ -111,17 +110,6 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
core.info(`Cache Size: ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B)`);
yield tar_1.extractTar(archivePath, compressionMethod);
core.info('Cache restored successfully');
- return cacheEntry.cacheKey;
- }
- catch (error) {
- const typedError = error;
- if (typedError.name === ValidationError.name) {
- throw error;
- }
- else {
- // Supress all non-validation cache related errors because caching should be optional
- core.warning(`Failed to restore: ${error.message}`);
- }
}
finally {
// Try to delete the archive to save space
@@ -132,7 +120,7 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
core.debug(`Failed to delete archive: ${error}`);
}
}
- return undefined;
+ return cacheEntry.cacheKey;
});
}
exports.restoreCache = restoreCache;
@@ -150,13 +138,10 @@ function saveCache(paths, key, options) {
checkPaths(paths);
checkKey(key);
const compressionMethod = yield utils.getCompressionMethod();
- let cacheId = -1;
+ let cacheId = null;
const cachePaths = yield utils.resolvePaths(paths);
core.debug('Cache Paths:');
core.debug(`${JSON.stringify(cachePaths)}`);
- if (cachePaths.length === 0) {
- throw new Error(`Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.`);
- }
const archiveFolder = yield utils.createTempDirectory();
const archivePath = path.join(archiveFolder, utils.getCacheFileName(compressionMethod));
core.debug(`Archive Path: ${archivePath}`);
@@ -189,18 +174,6 @@ function saveCache(paths, key, options) {
core.debug(`Saving Cache (ID: ${cacheId})`);
yield cacheHttpClient.saveCache(cacheId, archivePath, options);
}
- catch (error) {
- const typedError = error;
- if (typedError.name === ValidationError.name) {
- throw error;
- }
- else if (typedError.name === ReserveCacheError.name) {
- core.info(`Failed to save: ${typedError.message}`);
- }
- else {
- core.warning(`Failed to save: ${typedError.message}`);
- }
- }
finally {
// Try to delete the archive to save space
try {
@@ -674,7 +647,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(1825);
+const http_client_1 = __nccwpck_require__(9925);
const storage_blob_1 = __nccwpck_require__(4100);
const buffer = __importStar(__nccwpck_require__(4300));
const fs = __importStar(__nccwpck_require__(7147));
@@ -912,7 +885,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(1825);
+const http_client_1 = __nccwpck_require__(9925);
const constants_1 = __nccwpck_require__(8840);
function isSuccessStatusCode(statusCode) {
if (!statusCode) {
@@ -989,7 +962,7 @@ function retryTypedResponse(name, method, maxAttempts = constants_1.DefaultRetry
return __awaiter(this, void 0, void 0, function* () {
return yield retry(name, method, (response) => response.statusCode, maxAttempts, delay,
// If the error object contains the statusCode property, extract it and return
- // an TypedResponse so it can be processed by the retry logic.
+ // an ITypedResponse so it can be processed by the retry logic.
(error) => {
if (error instanceof http_client_1.HttpClientError) {
return {
@@ -1147,8 +1120,6 @@ function createTar(archiveFolder, sourceDirectories, compressionMethod) {
...getCompressionProgram(),
'-cf',
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
- '--exclude',
- cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'-P',
'-C',
workingDirectory.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
@@ -2321,774 +2292,6 @@ exports.SearchState = SearchState;
/***/ }),
-/***/ 2001:
-/***/ (function(__unused_webpack_module, exports) {
-
-"use strict";
-
-var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
- return new (P || (P = Promise))(function (resolve, reject) {
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
-};
-Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.PersonalAccessTokenCredentialHandler = exports.BearerCredentialHandler = exports.BasicCredentialHandler = void 0;
-class BasicCredentialHandler {
- constructor(username, password) {
- this.username = username;
- this.password = password;
- }
- prepareRequest(options) {
- if (!options.headers) {
- throw Error('The request has no headers');
- }
- options.headers['Authorization'] = `Basic ${Buffer.from(`${this.username}:${this.password}`).toString('base64')}`;
- }
- // This handler cannot handle 401
- canHandleAuthentication() {
- return false;
- }
- handleAuthentication() {
- return __awaiter(this, void 0, void 0, function* () {
- throw new Error('not implemented');
- });
- }
-}
-exports.BasicCredentialHandler = BasicCredentialHandler;
-class BearerCredentialHandler {
- constructor(token) {
- this.token = token;
- }
- // currently implements pre-authorization
- // TODO: support preAuth = false where it hooks on 401
- prepareRequest(options) {
- if (!options.headers) {
- throw Error('The request has no headers');
- }
- options.headers['Authorization'] = `Bearer ${this.token}`;
- }
- // This handler cannot handle 401
- canHandleAuthentication() {
- return false;
- }
- handleAuthentication() {
- return __awaiter(this, void 0, void 0, function* () {
- throw new Error('not implemented');
- });
- }
-}
-exports.BearerCredentialHandler = BearerCredentialHandler;
-class PersonalAccessTokenCredentialHandler {
- constructor(token) {
- this.token = token;
- }
- // currently implements pre-authorization
- // TODO: support preAuth = false where it hooks on 401
- prepareRequest(options) {
- if (!options.headers) {
- throw Error('The request has no headers');
- }
- options.headers['Authorization'] = `Basic ${Buffer.from(`PAT:${this.token}`).toString('base64')}`;
- }
- // This handler cannot handle 401
- canHandleAuthentication() {
- return false;
- }
- handleAuthentication() {
- return __awaiter(this, void 0, void 0, function* () {
- throw new Error('not implemented');
- });
- }
-}
-exports.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHandler;
-//# sourceMappingURL=auth.js.map
-
-/***/ }),
-
-/***/ 1825:
-/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
-
-"use strict";
-
-/* eslint-disable @typescript-eslint/no-explicit-any */
-var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
- if (k2 === undefined) k2 = k;
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
-}) : (function(o, m, k, k2) {
- if (k2 === undefined) k2 = k;
- o[k2] = m[k];
-}));
-var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
- Object.defineProperty(o, "default", { enumerable: true, value: v });
-}) : function(o, v) {
- o["default"] = v;
-});
-var __importStar = (this && this.__importStar) || function (mod) {
- if (mod && mod.__esModule) return mod;
- var result = {};
- if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
- __setModuleDefault(result, mod);
- return result;
-};
-var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
- return new (P || (P = Promise))(function (resolve, reject) {
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
-};
-Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.HttpClient = exports.isHttps = exports.HttpClientResponse = exports.HttpClientError = exports.getProxyUrl = exports.MediaTypes = exports.Headers = exports.HttpCodes = void 0;
-const http = __importStar(__nccwpck_require__(3685));
-const https = __importStar(__nccwpck_require__(5687));
-const pm = __importStar(__nccwpck_require__(4977));
-const tunnel = __importStar(__nccwpck_require__(4294));
-var HttpCodes;
-(function (HttpCodes) {
- HttpCodes[HttpCodes["OK"] = 200] = "OK";
- HttpCodes[HttpCodes["MultipleChoices"] = 300] = "MultipleChoices";
- HttpCodes[HttpCodes["MovedPermanently"] = 301] = "MovedPermanently";
- HttpCodes[HttpCodes["ResourceMoved"] = 302] = "ResourceMoved";
- HttpCodes[HttpCodes["SeeOther"] = 303] = "SeeOther";
- HttpCodes[HttpCodes["NotModified"] = 304] = "NotModified";
- HttpCodes[HttpCodes["UseProxy"] = 305] = "UseProxy";
- HttpCodes[HttpCodes["SwitchProxy"] = 306] = "SwitchProxy";
- HttpCodes[HttpCodes["TemporaryRedirect"] = 307] = "TemporaryRedirect";
- HttpCodes[HttpCodes["PermanentRedirect"] = 308] = "PermanentRedirect";
- HttpCodes[HttpCodes["BadRequest"] = 400] = "BadRequest";
- HttpCodes[HttpCodes["Unauthorized"] = 401] = "Unauthorized";
- HttpCodes[HttpCodes["PaymentRequired"] = 402] = "PaymentRequired";
- HttpCodes[HttpCodes["Forbidden"] = 403] = "Forbidden";
- HttpCodes[HttpCodes["NotFound"] = 404] = "NotFound";
- HttpCodes[HttpCodes["MethodNotAllowed"] = 405] = "MethodNotAllowed";
- HttpCodes[HttpCodes["NotAcceptable"] = 406] = "NotAcceptable";
- HttpCodes[HttpCodes["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
- HttpCodes[HttpCodes["RequestTimeout"] = 408] = "RequestTimeout";
- HttpCodes[HttpCodes["Conflict"] = 409] = "Conflict";
- HttpCodes[HttpCodes["Gone"] = 410] = "Gone";
- HttpCodes[HttpCodes["TooManyRequests"] = 429] = "TooManyRequests";
- HttpCodes[HttpCodes["InternalServerError"] = 500] = "InternalServerError";
- HttpCodes[HttpCodes["NotImplemented"] = 501] = "NotImplemented";
- HttpCodes[HttpCodes["BadGateway"] = 502] = "BadGateway";
- HttpCodes[HttpCodes["ServiceUnavailable"] = 503] = "ServiceUnavailable";
- HttpCodes[HttpCodes["GatewayTimeout"] = 504] = "GatewayTimeout";
-})(HttpCodes = exports.HttpCodes || (exports.HttpCodes = {}));
-var Headers;
-(function (Headers) {
- Headers["Accept"] = "accept";
- Headers["ContentType"] = "content-type";
-})(Headers = exports.Headers || (exports.Headers = {}));
-var MediaTypes;
-(function (MediaTypes) {
- MediaTypes["ApplicationJson"] = "application/json";
-})(MediaTypes = exports.MediaTypes || (exports.MediaTypes = {}));
-/**
- * Returns the proxy URL, depending upon the supplied url and proxy environment variables.
- * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
- */
-function getProxyUrl(serverUrl) {
- const proxyUrl = pm.getProxyUrl(new URL(serverUrl));
- return proxyUrl ? proxyUrl.href : '';
-}
-exports.getProxyUrl = getProxyUrl;
-const HttpRedirectCodes = [
- HttpCodes.MovedPermanently,
- HttpCodes.ResourceMoved,
- HttpCodes.SeeOther,
- HttpCodes.TemporaryRedirect,
- HttpCodes.PermanentRedirect
-];
-const HttpResponseRetryCodes = [
- HttpCodes.BadGateway,
- HttpCodes.ServiceUnavailable,
- HttpCodes.GatewayTimeout
-];
-const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD'];
-const ExponentialBackoffCeiling = 10;
-const ExponentialBackoffTimeSlice = 5;
-class HttpClientError extends Error {
- constructor(message, statusCode) {
- super(message);
- this.name = 'HttpClientError';
- this.statusCode = statusCode;
- Object.setPrototypeOf(this, HttpClientError.prototype);
- }
-}
-exports.HttpClientError = HttpClientError;
-class HttpClientResponse {
- constructor(message) {
- this.message = message;
- }
- readBody() {
- return __awaiter(this, void 0, void 0, function* () {
- return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
- let output = Buffer.alloc(0);
- this.message.on('data', (chunk) => {
- output = Buffer.concat([output, chunk]);
- });
- this.message.on('end', () => {
- resolve(output.toString());
- });
- }));
- });
- }
-}
-exports.HttpClientResponse = HttpClientResponse;
-function isHttps(requestUrl) {
- const parsedUrl = new URL(requestUrl);
- return parsedUrl.protocol === 'https:';
-}
-exports.isHttps = isHttps;
-class HttpClient {
- constructor(userAgent, handlers, requestOptions) {
- this._ignoreSslError = false;
- this._allowRedirects = true;
- this._allowRedirectDowngrade = false;
- this._maxRedirects = 50;
- this._allowRetries = false;
- this._maxRetries = 1;
- this._keepAlive = false;
- this._disposed = false;
- this.userAgent = userAgent;
- this.handlers = handlers || [];
- this.requestOptions = requestOptions;
- if (requestOptions) {
- if (requestOptions.ignoreSslError != null) {
- this._ignoreSslError = requestOptions.ignoreSslError;
- }
- this._socketTimeout = requestOptions.socketTimeout;
- if (requestOptions.allowRedirects != null) {
- this._allowRedirects = requestOptions.allowRedirects;
- }
- if (requestOptions.allowRedirectDowngrade != null) {
- this._allowRedirectDowngrade = requestOptions.allowRedirectDowngrade;
- }
- if (requestOptions.maxRedirects != null) {
- this._maxRedirects = Math.max(requestOptions.maxRedirects, 0);
- }
- if (requestOptions.keepAlive != null) {
- this._keepAlive = requestOptions.keepAlive;
- }
- if (requestOptions.allowRetries != null) {
- this._allowRetries = requestOptions.allowRetries;
- }
- if (requestOptions.maxRetries != null) {
- this._maxRetries = requestOptions.maxRetries;
- }
- }
- }
- options(requestUrl, additionalHeaders) {
- return __awaiter(this, void 0, void 0, function* () {
- return this.request('OPTIONS', requestUrl, null, additionalHeaders || {});
- });
- }
- get(requestUrl, additionalHeaders) {
- return __awaiter(this, void 0, void 0, function* () {
- return this.request('GET', requestUrl, null, additionalHeaders || {});
- });
- }
- del(requestUrl, additionalHeaders) {
- return __awaiter(this, void 0, void 0, function* () {
- return this.request('DELETE', requestUrl, null, additionalHeaders || {});
- });
- }
- post(requestUrl, data, additionalHeaders) {
- return __awaiter(this, void 0, void 0, function* () {
- return this.request('POST', requestUrl, data, additionalHeaders || {});
- });
- }
- patch(requestUrl, data, additionalHeaders) {
- return __awaiter(this, void 0, void 0, function* () {
- return this.request('PATCH', requestUrl, data, additionalHeaders || {});
- });
- }
- put(requestUrl, data, additionalHeaders) {
- return __awaiter(this, void 0, void 0, function* () {
- return this.request('PUT', requestUrl, data, additionalHeaders || {});
- });
- }
- head(requestUrl, additionalHeaders) {
- return __awaiter(this, void 0, void 0, function* () {
- return this.request('HEAD', requestUrl, null, additionalHeaders || {});
- });
- }
- sendStream(verb, requestUrl, stream, additionalHeaders) {
- return __awaiter(this, void 0, void 0, function* () {
- return this.request(verb, requestUrl, stream, additionalHeaders);
- });
- }
- /**
- * Gets a typed object from an endpoint
- * Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise
- */
- getJson(requestUrl, additionalHeaders = {}) {
- return __awaiter(this, void 0, void 0, function* () {
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- const res = yield this.get(requestUrl, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
- });
- }
- postJson(requestUrl, obj, additionalHeaders = {}) {
- return __awaiter(this, void 0, void 0, function* () {
- const data = JSON.stringify(obj, null, 2);
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
- const res = yield this.post(requestUrl, data, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
- });
- }
- putJson(requestUrl, obj, additionalHeaders = {}) {
- return __awaiter(this, void 0, void 0, function* () {
- const data = JSON.stringify(obj, null, 2);
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
- const res = yield this.put(requestUrl, data, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
- });
- }
- patchJson(requestUrl, obj, additionalHeaders = {}) {
- return __awaiter(this, void 0, void 0, function* () {
- const data = JSON.stringify(obj, null, 2);
- additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
- additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
- const res = yield this.patch(requestUrl, data, additionalHeaders);
- return this._processResponse(res, this.requestOptions);
- });
- }
- /**
- * Makes a raw http request.
- * All other methods such as get, post, patch, and request ultimately call this.
- * Prefer get, del, post and patch
- */
- request(verb, requestUrl, data, headers) {
- return __awaiter(this, void 0, void 0, function* () {
- if (this._disposed) {
- throw new Error('Client has already been disposed.');
- }
- const parsedUrl = new URL(requestUrl);
- let info = this._prepareRequest(verb, parsedUrl, headers);
- // Only perform retries on reads since writes may not be idempotent.
- const maxTries = this._allowRetries && RetryableHttpVerbs.includes(verb)
- ? this._maxRetries + 1
- : 1;
- let numTries = 0;
- let response;
- do {
- response = yield this.requestRaw(info, data);
- // Check if it's an authentication challenge
- if (response &&
- response.message &&
- response.message.statusCode === HttpCodes.Unauthorized) {
- let authenticationHandler;
- for (const handler of this.handlers) {
- if (handler.canHandleAuthentication(response)) {
- authenticationHandler = handler;
- break;
- }
- }
- if (authenticationHandler) {
- return authenticationHandler.handleAuthentication(this, info, data);
- }
- else {
- // We have received an unauthorized response but have no handlers to handle it.
- // Let the response return to the caller.
- return response;
- }
- }
- let redirectsRemaining = this._maxRedirects;
- while (response.message.statusCode &&
- HttpRedirectCodes.includes(response.message.statusCode) &&
- this._allowRedirects &&
- redirectsRemaining > 0) {
- const redirectUrl = response.message.headers['location'];
- if (!redirectUrl) {
- // if there's no location to redirect to, we won't
- break;
- }
- const parsedRedirectUrl = new URL(redirectUrl);
- if (parsedUrl.protocol === 'https:' &&
- parsedUrl.protocol !== parsedRedirectUrl.protocol &&
- !this._allowRedirectDowngrade) {
- throw new Error('Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.');
- }
- // we need to finish reading the response before reassigning response
- // which will leak the open socket.
- yield response.readBody();
- // strip authorization header if redirected to a different hostname
- if (parsedRedirectUrl.hostname !== parsedUrl.hostname) {
- for (const header in headers) {
- // header names are case insensitive
- if (header.toLowerCase() === 'authorization') {
- delete headers[header];
- }
- }
- }
- // let's make the request with the new redirectUrl
- info = this._prepareRequest(verb, parsedRedirectUrl, headers);
- response = yield this.requestRaw(info, data);
- redirectsRemaining--;
- }
- if (!response.message.statusCode ||
- !HttpResponseRetryCodes.includes(response.message.statusCode)) {
- // If not a retry code, return immediately instead of retrying
- return response;
- }
- numTries += 1;
- if (numTries < maxTries) {
- yield response.readBody();
- yield this._performExponentialBackoff(numTries);
- }
- } while (numTries < maxTries);
- return response;
- });
- }
- /**
- * Needs to be called if keepAlive is set to true in request options.
- */
- dispose() {
- if (this._agent) {
- this._agent.destroy();
- }
- this._disposed = true;
- }
- /**
- * Raw request.
- * @param info
- * @param data
- */
- requestRaw(info, data) {
- return __awaiter(this, void 0, void 0, function* () {
- return new Promise((resolve, reject) => {
- function callbackForResult(err, res) {
- if (err) {
- reject(err);
- }
- else if (!res) {
- // If `err` is not passed, then `res` must be passed.
- reject(new Error('Unknown error'));
- }
- else {
- resolve(res);
- }
- }
- this.requestRawWithCallback(info, data, callbackForResult);
- });
- });
- }
- /**
- * Raw request with callback.
- * @param info
- * @param data
- * @param onResult
- */
- requestRawWithCallback(info, data, onResult) {
- if (typeof data === 'string') {
- if (!info.options.headers) {
- info.options.headers = {};
- }
- info.options.headers['Content-Length'] = Buffer.byteLength(data, 'utf8');
- }
- let callbackCalled = false;
- function handleResult(err, res) {
- if (!callbackCalled) {
- callbackCalled = true;
- onResult(err, res);
- }
- }
- const req = info.httpModule.request(info.options, (msg) => {
- const res = new HttpClientResponse(msg);
- handleResult(undefined, res);
- });
- let socket;
- req.on('socket', sock => {
- socket = sock;
- });
- // If we ever get disconnected, we want the socket to timeout eventually
- req.setTimeout(this._socketTimeout || 3 * 60000, () => {
- if (socket) {
- socket.end();
- }
- handleResult(new Error(`Request timeout: ${info.options.path}`));
- });
- req.on('error', function (err) {
- // err has statusCode property
- // res should have headers
- handleResult(err);
- });
- if (data && typeof data === 'string') {
- req.write(data, 'utf8');
- }
- if (data && typeof data !== 'string') {
- data.on('close', function () {
- req.end();
- });
- data.pipe(req);
- }
- else {
- req.end();
- }
- }
- /**
- * Gets an http agent. This function is useful when you need an http agent that handles
- * routing through a proxy server - depending upon the url and proxy environment variables.
- * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
- */
- getAgent(serverUrl) {
- const parsedUrl = new URL(serverUrl);
- return this._getAgent(parsedUrl);
- }
- _prepareRequest(method, requestUrl, headers) {
- const info = {};
- info.parsedUrl = requestUrl;
- const usingSsl = info.parsedUrl.protocol === 'https:';
- info.httpModule = usingSsl ? https : http;
- const defaultPort = usingSsl ? 443 : 80;
- info.options = {};
- info.options.host = info.parsedUrl.hostname;
- info.options.port = info.parsedUrl.port
- ? parseInt(info.parsedUrl.port)
- : defaultPort;
- info.options.path =
- (info.parsedUrl.pathname || '') + (info.parsedUrl.search || '');
- info.options.method = method;
- info.options.headers = this._mergeHeaders(headers);
- if (this.userAgent != null) {
- info.options.headers['user-agent'] = this.userAgent;
- }
- info.options.agent = this._getAgent(info.parsedUrl);
- // gives handlers an opportunity to participate
- if (this.handlers) {
- for (const handler of this.handlers) {
- handler.prepareRequest(info.options);
- }
- }
- return info;
- }
- _mergeHeaders(headers) {
- if (this.requestOptions && this.requestOptions.headers) {
- return Object.assign({}, lowercaseKeys(this.requestOptions.headers), lowercaseKeys(headers || {}));
- }
- return lowercaseKeys(headers || {});
- }
- _getExistingOrDefaultHeader(additionalHeaders, header, _default) {
- let clientHeader;
- if (this.requestOptions && this.requestOptions.headers) {
- clientHeader = lowercaseKeys(this.requestOptions.headers)[header];
- }
- return additionalHeaders[header] || clientHeader || _default;
- }
- _getAgent(parsedUrl) {
- let agent;
- const proxyUrl = pm.getProxyUrl(parsedUrl);
- const useProxy = proxyUrl && proxyUrl.hostname;
- if (this._keepAlive && useProxy) {
- agent = this._proxyAgent;
- }
- if (this._keepAlive && !useProxy) {
- agent = this._agent;
- }
- // if agent is already assigned use that agent.
- if (agent) {
- return agent;
- }
- const usingSsl = parsedUrl.protocol === 'https:';
- let maxSockets = 100;
- if (this.requestOptions) {
- maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets;
- }
- // This is `useProxy` again, but we need to check `proxyURl` directly for TypeScripts's flow analysis.
- if (proxyUrl && proxyUrl.hostname) {
- const agentOptions = {
- maxSockets,
- keepAlive: this._keepAlive,
- proxy: Object.assign(Object.assign({}, ((proxyUrl.username || proxyUrl.password) && {
- proxyAuth: `${proxyUrl.username}:${proxyUrl.password}`
- })), { host: proxyUrl.hostname, port: proxyUrl.port })
- };
- let tunnelAgent;
- const overHttps = proxyUrl.protocol === 'https:';
- if (usingSsl) {
- tunnelAgent = overHttps ? tunnel.httpsOverHttps : tunnel.httpsOverHttp;
- }
- else {
- tunnelAgent = overHttps ? tunnel.httpOverHttps : tunnel.httpOverHttp;
- }
- agent = tunnelAgent(agentOptions);
- this._proxyAgent = agent;
- }
- // if reusing agent across request and tunneling agent isn't assigned create a new agent
- if (this._keepAlive && !agent) {
- const options = { keepAlive: this._keepAlive, maxSockets };
- agent = usingSsl ? new https.Agent(options) : new http.Agent(options);
- this._agent = agent;
- }
- // if not using private agent and tunnel agent isn't setup then use global agent
- if (!agent) {
- agent = usingSsl ? https.globalAgent : http.globalAgent;
- }
- if (usingSsl && this._ignoreSslError) {
- // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process
- // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options
- // we have to cast it to any and change it directly
- agent.options = Object.assign(agent.options || {}, {
- rejectUnauthorized: false
- });
- }
- return agent;
- }
- _performExponentialBackoff(retryNumber) {
- return __awaiter(this, void 0, void 0, function* () {
- retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber);
- const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber);
- return new Promise(resolve => setTimeout(() => resolve(), ms));
- });
- }
- _processResponse(res, options) {
- return __awaiter(this, void 0, void 0, function* () {
- return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
- const statusCode = res.message.statusCode || 0;
- const response = {
- statusCode,
- result: null,
- headers: {}
- };
- // not found leads to null obj returned
- if (statusCode === HttpCodes.NotFound) {
- resolve(response);
- }
- // get the result from the body
- function dateTimeDeserializer(key, value) {
- if (typeof value === 'string') {
- const a = new Date(value);
- if (!isNaN(a.valueOf())) {
- return a;
- }
- }
- return value;
- }
- let obj;
- let contents;
- try {
- contents = yield res.readBody();
- if (contents && contents.length > 0) {
- if (options && options.deserializeDates) {
- obj = JSON.parse(contents, dateTimeDeserializer);
- }
- else {
- obj = JSON.parse(contents);
- }
- response.result = obj;
- }
- response.headers = res.message.headers;
- }
- catch (err) {
- // Invalid resource (contents not json); leaving result obj null
- }
- // note that 3xx redirects are handled by the http layer.
- if (statusCode > 299) {
- let msg;
- // if exception/error in body, attempt to get better error
- if (obj && obj.message) {
- msg = obj.message;
- }
- else if (contents && contents.length > 0) {
- // it may be the case that the exception is in the body message as string
- msg = contents;
- }
- else {
- msg = `Failed request: (${statusCode})`;
- }
- const err = new HttpClientError(msg, statusCode);
- err.result = response.result;
- reject(err);
- }
- else {
- resolve(response);
- }
- }));
- });
- }
-}
-exports.HttpClient = HttpClient;
-const lowercaseKeys = (obj) => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
-//# sourceMappingURL=index.js.map
-
-/***/ }),
-
-/***/ 4977:
-/***/ ((__unused_webpack_module, exports) => {
-
-"use strict";
-
-Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.checkBypass = exports.getProxyUrl = void 0;
-function getProxyUrl(reqUrl) {
- const usingSsl = reqUrl.protocol === 'https:';
- if (checkBypass(reqUrl)) {
- return undefined;
- }
- const proxyVar = (() => {
- if (usingSsl) {
- return process.env['https_proxy'] || process.env['HTTPS_PROXY'];
- }
- else {
- return process.env['http_proxy'] || process.env['HTTP_PROXY'];
- }
- })();
- if (proxyVar) {
- return new URL(proxyVar);
- }
- else {
- return undefined;
- }
-}
-exports.getProxyUrl = getProxyUrl;
-function checkBypass(reqUrl) {
- if (!reqUrl.hostname) {
- return false;
- }
- const noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || '';
- if (!noProxy) {
- return false;
- }
- // Determine the request port
- let reqPort;
- if (reqUrl.port) {
- reqPort = Number(reqUrl.port);
- }
- else if (reqUrl.protocol === 'http:') {
- reqPort = 80;
- }
- else if (reqUrl.protocol === 'https:') {
- reqPort = 443;
- }
- // Format the request hostname and hostname with port
- const upperReqHosts = [reqUrl.hostname.toUpperCase()];
- if (typeof reqPort === 'number') {
- upperReqHosts.push(`${upperReqHosts[0]}:${reqPort}`);
- }
- // Compare request host against noproxy
- for (const upperNoProxyItem of noProxy
- .split(',')
- .map(x => x.trim().toUpperCase())
- .filter(x => x)) {
- if (upperReqHosts.some(x => x === upperNoProxyItem)) {
- return true;
- }
- }
- return false;
-}
-exports.checkBypass = checkBypass;
-//# sourceMappingURL=proxy.js.map
-
-/***/ }),
-
/***/ 3771:
/***/ ((module, exports) => {
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 4f85be74..b98b9af2 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -90,18 +90,17 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
checkKey(key);
}
const compressionMethod = yield utils.getCompressionMethod();
- let archivePath = '';
+ // path are needed to compute version
+ const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
+ compressionMethod
+ });
+ if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
+ // Cache not found
+ return undefined;
+ }
+ const archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
+ core.debug(`Archive Path: ${archivePath}`);
try {
- // path are needed to compute version
- const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
- compressionMethod
- });
- if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
- // Cache not found
- return undefined;
- }
- archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
- core.debug(`Archive Path: ${archivePath}`);
// Download the cache from the cache entry
yield cacheHttpClient.downloadCache(cacheEntry.archiveLocation, archivePath, options);
if (core.isDebug()) {
@@ -111,17 +110,6 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
core.info(`Cache Size: ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B)`);
yield tar_1.extractTar(archivePath, compressionMethod);
core.info('Cache restored successfully');
- return cacheEntry.cacheKey;
- }
- catch (error) {
- const typedError = error;
- if (typedError.name === ValidationError.name) {
- throw error;
- }
- else {
- // Supress all non-validation cache related errors because caching should be optional
- core.warning(`Failed to restore: ${error.message}`);
- }
}
finally {
// Try to delete the archive to save space
@@ -132,7 +120,7 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
core.debug(`Failed to delete archive: ${error}`);
}
}
- return undefined;
+ return cacheEntry.cacheKey;
});
}
exports.restoreCache = restoreCache;
@@ -150,13 +138,10 @@ function saveCache(paths, key, options) {
checkPaths(paths);
checkKey(key);
const compressionMethod = yield utils.getCompressionMethod();
- let cacheId = -1;
+ let cacheId = null;
const cachePaths = yield utils.resolvePaths(paths);
core.debug('Cache Paths:');
core.debug(`${JSON.stringify(cachePaths)}`);
- if (cachePaths.length === 0) {
- throw new Error(`Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.`);
- }
const archiveFolder = yield utils.createTempDirectory();
const archivePath = path.join(archiveFolder, utils.getCacheFileName(compressionMethod));
core.debug(`Archive Path: ${archivePath}`);
@@ -189,18 +174,6 @@ function saveCache(paths, key, options) {
core.debug(`Saving Cache (ID: ${cacheId})`);
yield cacheHttpClient.saveCache(cacheId, archivePath, options);
}
- catch (error) {
- const typedError = error;
- if (typedError.name === ValidationError.name) {
- throw error;
- }
- else if (typedError.name === ReserveCacheError.name) {
- core.info(`Failed to save: ${typedError.message}`);
- }
- else {
- core.warning(`Failed to save: ${typedError.message}`);
- }
- }
finally {
// Try to delete the archive to save space
try {
@@ -241,8 +214,8 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(1825);
-const auth_1 = __nccwpck_require__(2001);
+const http_client_1 = __nccwpck_require__(9925);
+const auth_1 = __nccwpck_require__(3702);
const crypto = __importStar(__nccwpck_require__(6113));
const fs = __importStar(__nccwpck_require__(7147));
const url_1 = __nccwpck_require__(7310);
@@ -674,7 +647,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(1825);
+const http_client_1 = __nccwpck_require__(9925);
const storage_blob_1 = __nccwpck_require__(4100);
const buffer = __importStar(__nccwpck_require__(4300));
const fs = __importStar(__nccwpck_require__(7147));
@@ -989,7 +962,7 @@ function retryTypedResponse(name, method, maxAttempts = constants_1.DefaultRetry
return __awaiter(this, void 0, void 0, function* () {
return yield retry(name, method, (response) => response.statusCode, maxAttempts, delay,
// If the error object contains the statusCode property, extract it and return
- // an TypedResponse so it can be processed by the retry logic.
+ // an ITypedResponse so it can be processed by the retry logic.
(error) => {
if (error instanceof http_client_1.HttpClientError) {
return {
@@ -1147,8 +1120,6 @@ function createTar(archiveFolder, sourceDirectories, compressionMethod) {
...getCompressionProgram(),
'-cf',
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
- '--exclude',
- cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'-P',
'-C',
workingDirectory.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
From 41b91104eac18e0699aba059eb354c218d851adc Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Thu, 30 Jun 2022 14:26:40 +0200
Subject: [PATCH 22/77] Rebuild action
---
.../npm/@actions/http-client-1.0.11.dep.yml | 32 +
dist/cache-save/index.js | 831 +++++++++++++++++-
dist/setup/index.js | 831 +++++++++++++++++-
3 files changed, 1660 insertions(+), 34 deletions(-)
create mode 100644 .licenses/npm/@actions/http-client-1.0.11.dep.yml
diff --git a/.licenses/npm/@actions/http-client-1.0.11.dep.yml b/.licenses/npm/@actions/http-client-1.0.11.dep.yml
new file mode 100644
index 00000000..43316cbc
--- /dev/null
+++ b/.licenses/npm/@actions/http-client-1.0.11.dep.yml
@@ -0,0 +1,32 @@
+---
+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: []
diff --git a/dist/cache-save/index.js b/dist/cache-save/index.js
index 8ede282a..b3fd8a73 100644
--- a/dist/cache-save/index.js
+++ b/dist/cache-save/index.js
@@ -90,17 +90,18 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
checkKey(key);
}
const compressionMethod = yield utils.getCompressionMethod();
- // path are needed to compute version
- const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
- compressionMethod
- });
- if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
- // Cache not found
- return undefined;
- }
- const archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
- core.debug(`Archive Path: ${archivePath}`);
+ let archivePath = '';
try {
+ // path are needed to compute version
+ const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
+ compressionMethod
+ });
+ if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
+ // Cache not found
+ return undefined;
+ }
+ archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
+ core.debug(`Archive Path: ${archivePath}`);
// Download the cache from the cache entry
yield cacheHttpClient.downloadCache(cacheEntry.archiveLocation, archivePath, options);
if (core.isDebug()) {
@@ -110,6 +111,17 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
core.info(`Cache Size: ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B)`);
yield tar_1.extractTar(archivePath, compressionMethod);
core.info('Cache restored successfully');
+ return cacheEntry.cacheKey;
+ }
+ catch (error) {
+ const typedError = error;
+ if (typedError.name === ValidationError.name) {
+ throw error;
+ }
+ else {
+ // Supress all non-validation cache related errors because caching should be optional
+ core.warning(`Failed to restore: ${error.message}`);
+ }
}
finally {
// Try to delete the archive to save space
@@ -120,7 +132,7 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
core.debug(`Failed to delete archive: ${error}`);
}
}
- return cacheEntry.cacheKey;
+ return undefined;
});
}
exports.restoreCache = restoreCache;
@@ -138,10 +150,13 @@ function saveCache(paths, key, options) {
checkPaths(paths);
checkKey(key);
const compressionMethod = yield utils.getCompressionMethod();
- let cacheId = null;
+ let cacheId = -1;
const cachePaths = yield utils.resolvePaths(paths);
core.debug('Cache Paths:');
core.debug(`${JSON.stringify(cachePaths)}`);
+ if (cachePaths.length === 0) {
+ throw new Error(`Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.`);
+ }
const archiveFolder = yield utils.createTempDirectory();
const archivePath = path.join(archiveFolder, utils.getCacheFileName(compressionMethod));
core.debug(`Archive Path: ${archivePath}`);
@@ -174,6 +189,18 @@ function saveCache(paths, key, options) {
core.debug(`Saving Cache (ID: ${cacheId})`);
yield cacheHttpClient.saveCache(cacheId, archivePath, options);
}
+ catch (error) {
+ const typedError = error;
+ if (typedError.name === ValidationError.name) {
+ throw error;
+ }
+ else if (typedError.name === ReserveCacheError.name) {
+ core.info(`Failed to save: ${typedError.message}`);
+ }
+ else {
+ core.warning(`Failed to save: ${typedError.message}`);
+ }
+ }
finally {
// Try to delete the archive to save space
try {
@@ -214,8 +241,8 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(9925);
-const auth_1 = __nccwpck_require__(3702);
+const http_client_1 = __nccwpck_require__(1825);
+const auth_1 = __nccwpck_require__(2001);
const crypto = __importStar(__nccwpck_require__(6113));
const fs = __importStar(__nccwpck_require__(7147));
const url_1 = __nccwpck_require__(7310);
@@ -647,7 +674,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(9925);
+const http_client_1 = __nccwpck_require__(1825);
const storage_blob_1 = __nccwpck_require__(4100);
const buffer = __importStar(__nccwpck_require__(4300));
const fs = __importStar(__nccwpck_require__(7147));
@@ -885,7 +912,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(9925);
+const http_client_1 = __nccwpck_require__(1825);
const constants_1 = __nccwpck_require__(8840);
function isSuccessStatusCode(statusCode) {
if (!statusCode) {
@@ -962,7 +989,7 @@ function retryTypedResponse(name, method, maxAttempts = constants_1.DefaultRetry
return __awaiter(this, void 0, void 0, function* () {
return yield retry(name, method, (response) => response.statusCode, maxAttempts, delay,
// If the error object contains the statusCode property, extract it and return
- // an ITypedResponse so it can be processed by the retry logic.
+ // an TypedResponse so it can be processed by the retry logic.
(error) => {
if (error instanceof http_client_1.HttpClientError) {
return {
@@ -1120,6 +1147,8 @@ function createTar(archiveFolder, sourceDirectories, compressionMethod) {
...getCompressionProgram(),
'-cf',
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
+ '--exclude',
+ cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'-P',
'-C',
workingDirectory.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
@@ -2292,6 +2321,774 @@ exports.SearchState = SearchState;
/***/ }),
+/***/ 2001:
+/***/ (function(__unused_webpack_module, exports) {
+
+"use strict";
+
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.PersonalAccessTokenCredentialHandler = exports.BearerCredentialHandler = exports.BasicCredentialHandler = void 0;
+class BasicCredentialHandler {
+ constructor(username, password) {
+ this.username = username;
+ this.password = password;
+ }
+ prepareRequest(options) {
+ if (!options.headers) {
+ throw Error('The request has no headers');
+ }
+ options.headers['Authorization'] = `Basic ${Buffer.from(`${this.username}:${this.password}`).toString('base64')}`;
+ }
+ // This handler cannot handle 401
+ canHandleAuthentication() {
+ return false;
+ }
+ handleAuthentication() {
+ return __awaiter(this, void 0, void 0, function* () {
+ throw new Error('not implemented');
+ });
+ }
+}
+exports.BasicCredentialHandler = BasicCredentialHandler;
+class BearerCredentialHandler {
+ constructor(token) {
+ this.token = token;
+ }
+ // currently implements pre-authorization
+ // TODO: support preAuth = false where it hooks on 401
+ prepareRequest(options) {
+ if (!options.headers) {
+ throw Error('The request has no headers');
+ }
+ options.headers['Authorization'] = `Bearer ${this.token}`;
+ }
+ // This handler cannot handle 401
+ canHandleAuthentication() {
+ return false;
+ }
+ handleAuthentication() {
+ return __awaiter(this, void 0, void 0, function* () {
+ throw new Error('not implemented');
+ });
+ }
+}
+exports.BearerCredentialHandler = BearerCredentialHandler;
+class PersonalAccessTokenCredentialHandler {
+ constructor(token) {
+ this.token = token;
+ }
+ // currently implements pre-authorization
+ // TODO: support preAuth = false where it hooks on 401
+ prepareRequest(options) {
+ if (!options.headers) {
+ throw Error('The request has no headers');
+ }
+ options.headers['Authorization'] = `Basic ${Buffer.from(`PAT:${this.token}`).toString('base64')}`;
+ }
+ // This handler cannot handle 401
+ canHandleAuthentication() {
+ return false;
+ }
+ handleAuthentication() {
+ return __awaiter(this, void 0, void 0, function* () {
+ throw new Error('not implemented');
+ });
+ }
+}
+exports.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHandler;
+//# sourceMappingURL=auth.js.map
+
+/***/ }),
+
+/***/ 1825:
+/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
+
+"use strict";
+
+/* eslint-disable @typescript-eslint/no-explicit-any */
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.HttpClient = exports.isHttps = exports.HttpClientResponse = exports.HttpClientError = exports.getProxyUrl = exports.MediaTypes = exports.Headers = exports.HttpCodes = void 0;
+const http = __importStar(__nccwpck_require__(3685));
+const https = __importStar(__nccwpck_require__(5687));
+const pm = __importStar(__nccwpck_require__(4977));
+const tunnel = __importStar(__nccwpck_require__(4294));
+var HttpCodes;
+(function (HttpCodes) {
+ HttpCodes[HttpCodes["OK"] = 200] = "OK";
+ HttpCodes[HttpCodes["MultipleChoices"] = 300] = "MultipleChoices";
+ HttpCodes[HttpCodes["MovedPermanently"] = 301] = "MovedPermanently";
+ HttpCodes[HttpCodes["ResourceMoved"] = 302] = "ResourceMoved";
+ HttpCodes[HttpCodes["SeeOther"] = 303] = "SeeOther";
+ HttpCodes[HttpCodes["NotModified"] = 304] = "NotModified";
+ HttpCodes[HttpCodes["UseProxy"] = 305] = "UseProxy";
+ HttpCodes[HttpCodes["SwitchProxy"] = 306] = "SwitchProxy";
+ HttpCodes[HttpCodes["TemporaryRedirect"] = 307] = "TemporaryRedirect";
+ HttpCodes[HttpCodes["PermanentRedirect"] = 308] = "PermanentRedirect";
+ HttpCodes[HttpCodes["BadRequest"] = 400] = "BadRequest";
+ HttpCodes[HttpCodes["Unauthorized"] = 401] = "Unauthorized";
+ HttpCodes[HttpCodes["PaymentRequired"] = 402] = "PaymentRequired";
+ HttpCodes[HttpCodes["Forbidden"] = 403] = "Forbidden";
+ HttpCodes[HttpCodes["NotFound"] = 404] = "NotFound";
+ HttpCodes[HttpCodes["MethodNotAllowed"] = 405] = "MethodNotAllowed";
+ HttpCodes[HttpCodes["NotAcceptable"] = 406] = "NotAcceptable";
+ HttpCodes[HttpCodes["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
+ HttpCodes[HttpCodes["RequestTimeout"] = 408] = "RequestTimeout";
+ HttpCodes[HttpCodes["Conflict"] = 409] = "Conflict";
+ HttpCodes[HttpCodes["Gone"] = 410] = "Gone";
+ HttpCodes[HttpCodes["TooManyRequests"] = 429] = "TooManyRequests";
+ HttpCodes[HttpCodes["InternalServerError"] = 500] = "InternalServerError";
+ HttpCodes[HttpCodes["NotImplemented"] = 501] = "NotImplemented";
+ HttpCodes[HttpCodes["BadGateway"] = 502] = "BadGateway";
+ HttpCodes[HttpCodes["ServiceUnavailable"] = 503] = "ServiceUnavailable";
+ HttpCodes[HttpCodes["GatewayTimeout"] = 504] = "GatewayTimeout";
+})(HttpCodes = exports.HttpCodes || (exports.HttpCodes = {}));
+var Headers;
+(function (Headers) {
+ Headers["Accept"] = "accept";
+ Headers["ContentType"] = "content-type";
+})(Headers = exports.Headers || (exports.Headers = {}));
+var MediaTypes;
+(function (MediaTypes) {
+ MediaTypes["ApplicationJson"] = "application/json";
+})(MediaTypes = exports.MediaTypes || (exports.MediaTypes = {}));
+/**
+ * Returns the proxy URL, depending upon the supplied url and proxy environment variables.
+ * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
+ */
+function getProxyUrl(serverUrl) {
+ const proxyUrl = pm.getProxyUrl(new URL(serverUrl));
+ return proxyUrl ? proxyUrl.href : '';
+}
+exports.getProxyUrl = getProxyUrl;
+const HttpRedirectCodes = [
+ HttpCodes.MovedPermanently,
+ HttpCodes.ResourceMoved,
+ HttpCodes.SeeOther,
+ HttpCodes.TemporaryRedirect,
+ HttpCodes.PermanentRedirect
+];
+const HttpResponseRetryCodes = [
+ HttpCodes.BadGateway,
+ HttpCodes.ServiceUnavailable,
+ HttpCodes.GatewayTimeout
+];
+const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD'];
+const ExponentialBackoffCeiling = 10;
+const ExponentialBackoffTimeSlice = 5;
+class HttpClientError extends Error {
+ constructor(message, statusCode) {
+ super(message);
+ this.name = 'HttpClientError';
+ this.statusCode = statusCode;
+ Object.setPrototypeOf(this, HttpClientError.prototype);
+ }
+}
+exports.HttpClientError = HttpClientError;
+class HttpClientResponse {
+ constructor(message) {
+ this.message = message;
+ }
+ readBody() {
+ return __awaiter(this, void 0, void 0, function* () {
+ return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
+ let output = Buffer.alloc(0);
+ this.message.on('data', (chunk) => {
+ output = Buffer.concat([output, chunk]);
+ });
+ this.message.on('end', () => {
+ resolve(output.toString());
+ });
+ }));
+ });
+ }
+}
+exports.HttpClientResponse = HttpClientResponse;
+function isHttps(requestUrl) {
+ const parsedUrl = new URL(requestUrl);
+ return parsedUrl.protocol === 'https:';
+}
+exports.isHttps = isHttps;
+class HttpClient {
+ constructor(userAgent, handlers, requestOptions) {
+ this._ignoreSslError = false;
+ this._allowRedirects = true;
+ this._allowRedirectDowngrade = false;
+ this._maxRedirects = 50;
+ this._allowRetries = false;
+ this._maxRetries = 1;
+ this._keepAlive = false;
+ this._disposed = false;
+ this.userAgent = userAgent;
+ this.handlers = handlers || [];
+ this.requestOptions = requestOptions;
+ if (requestOptions) {
+ if (requestOptions.ignoreSslError != null) {
+ this._ignoreSslError = requestOptions.ignoreSslError;
+ }
+ this._socketTimeout = requestOptions.socketTimeout;
+ if (requestOptions.allowRedirects != null) {
+ this._allowRedirects = requestOptions.allowRedirects;
+ }
+ if (requestOptions.allowRedirectDowngrade != null) {
+ this._allowRedirectDowngrade = requestOptions.allowRedirectDowngrade;
+ }
+ if (requestOptions.maxRedirects != null) {
+ this._maxRedirects = Math.max(requestOptions.maxRedirects, 0);
+ }
+ if (requestOptions.keepAlive != null) {
+ this._keepAlive = requestOptions.keepAlive;
+ }
+ if (requestOptions.allowRetries != null) {
+ this._allowRetries = requestOptions.allowRetries;
+ }
+ if (requestOptions.maxRetries != null) {
+ this._maxRetries = requestOptions.maxRetries;
+ }
+ }
+ }
+ options(requestUrl, additionalHeaders) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('OPTIONS', requestUrl, null, additionalHeaders || {});
+ });
+ }
+ get(requestUrl, additionalHeaders) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('GET', requestUrl, null, additionalHeaders || {});
+ });
+ }
+ del(requestUrl, additionalHeaders) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('DELETE', requestUrl, null, additionalHeaders || {});
+ });
+ }
+ post(requestUrl, data, additionalHeaders) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('POST', requestUrl, data, additionalHeaders || {});
+ });
+ }
+ patch(requestUrl, data, additionalHeaders) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('PATCH', requestUrl, data, additionalHeaders || {});
+ });
+ }
+ put(requestUrl, data, additionalHeaders) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('PUT', requestUrl, data, additionalHeaders || {});
+ });
+ }
+ head(requestUrl, additionalHeaders) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('HEAD', requestUrl, null, additionalHeaders || {});
+ });
+ }
+ sendStream(verb, requestUrl, stream, additionalHeaders) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request(verb, requestUrl, stream, additionalHeaders);
+ });
+ }
+ /**
+ * Gets a typed object from an endpoint
+ * Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise
+ */
+ getJson(requestUrl, additionalHeaders = {}) {
+ return __awaiter(this, void 0, void 0, function* () {
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ const res = yield this.get(requestUrl, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ });
+ }
+ postJson(requestUrl, obj, additionalHeaders = {}) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const data = JSON.stringify(obj, null, 2);
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
+ const res = yield this.post(requestUrl, data, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ });
+ }
+ putJson(requestUrl, obj, additionalHeaders = {}) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const data = JSON.stringify(obj, null, 2);
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
+ const res = yield this.put(requestUrl, data, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ });
+ }
+ patchJson(requestUrl, obj, additionalHeaders = {}) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const data = JSON.stringify(obj, null, 2);
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
+ const res = yield this.patch(requestUrl, data, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ });
+ }
+ /**
+ * Makes a raw http request.
+ * All other methods such as get, post, patch, and request ultimately call this.
+ * Prefer get, del, post and patch
+ */
+ request(verb, requestUrl, data, headers) {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (this._disposed) {
+ throw new Error('Client has already been disposed.');
+ }
+ const parsedUrl = new URL(requestUrl);
+ let info = this._prepareRequest(verb, parsedUrl, headers);
+ // Only perform retries on reads since writes may not be idempotent.
+ const maxTries = this._allowRetries && RetryableHttpVerbs.includes(verb)
+ ? this._maxRetries + 1
+ : 1;
+ let numTries = 0;
+ let response;
+ do {
+ response = yield this.requestRaw(info, data);
+ // Check if it's an authentication challenge
+ if (response &&
+ response.message &&
+ response.message.statusCode === HttpCodes.Unauthorized) {
+ let authenticationHandler;
+ for (const handler of this.handlers) {
+ if (handler.canHandleAuthentication(response)) {
+ authenticationHandler = handler;
+ break;
+ }
+ }
+ if (authenticationHandler) {
+ return authenticationHandler.handleAuthentication(this, info, data);
+ }
+ else {
+ // We have received an unauthorized response but have no handlers to handle it.
+ // Let the response return to the caller.
+ return response;
+ }
+ }
+ let redirectsRemaining = this._maxRedirects;
+ while (response.message.statusCode &&
+ HttpRedirectCodes.includes(response.message.statusCode) &&
+ this._allowRedirects &&
+ redirectsRemaining > 0) {
+ const redirectUrl = response.message.headers['location'];
+ if (!redirectUrl) {
+ // if there's no location to redirect to, we won't
+ break;
+ }
+ const parsedRedirectUrl = new URL(redirectUrl);
+ if (parsedUrl.protocol === 'https:' &&
+ parsedUrl.protocol !== parsedRedirectUrl.protocol &&
+ !this._allowRedirectDowngrade) {
+ throw new Error('Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.');
+ }
+ // we need to finish reading the response before reassigning response
+ // which will leak the open socket.
+ yield response.readBody();
+ // strip authorization header if redirected to a different hostname
+ if (parsedRedirectUrl.hostname !== parsedUrl.hostname) {
+ for (const header in headers) {
+ // header names are case insensitive
+ if (header.toLowerCase() === 'authorization') {
+ delete headers[header];
+ }
+ }
+ }
+ // let's make the request with the new redirectUrl
+ info = this._prepareRequest(verb, parsedRedirectUrl, headers);
+ response = yield this.requestRaw(info, data);
+ redirectsRemaining--;
+ }
+ if (!response.message.statusCode ||
+ !HttpResponseRetryCodes.includes(response.message.statusCode)) {
+ // If not a retry code, return immediately instead of retrying
+ return response;
+ }
+ numTries += 1;
+ if (numTries < maxTries) {
+ yield response.readBody();
+ yield this._performExponentialBackoff(numTries);
+ }
+ } while (numTries < maxTries);
+ return response;
+ });
+ }
+ /**
+ * Needs to be called if keepAlive is set to true in request options.
+ */
+ dispose() {
+ if (this._agent) {
+ this._agent.destroy();
+ }
+ this._disposed = true;
+ }
+ /**
+ * Raw request.
+ * @param info
+ * @param data
+ */
+ requestRaw(info, data) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return new Promise((resolve, reject) => {
+ function callbackForResult(err, res) {
+ if (err) {
+ reject(err);
+ }
+ else if (!res) {
+ // If `err` is not passed, then `res` must be passed.
+ reject(new Error('Unknown error'));
+ }
+ else {
+ resolve(res);
+ }
+ }
+ this.requestRawWithCallback(info, data, callbackForResult);
+ });
+ });
+ }
+ /**
+ * Raw request with callback.
+ * @param info
+ * @param data
+ * @param onResult
+ */
+ requestRawWithCallback(info, data, onResult) {
+ if (typeof data === 'string') {
+ if (!info.options.headers) {
+ info.options.headers = {};
+ }
+ info.options.headers['Content-Length'] = Buffer.byteLength(data, 'utf8');
+ }
+ let callbackCalled = false;
+ function handleResult(err, res) {
+ if (!callbackCalled) {
+ callbackCalled = true;
+ onResult(err, res);
+ }
+ }
+ const req = info.httpModule.request(info.options, (msg) => {
+ const res = new HttpClientResponse(msg);
+ handleResult(undefined, res);
+ });
+ let socket;
+ req.on('socket', sock => {
+ socket = sock;
+ });
+ // If we ever get disconnected, we want the socket to timeout eventually
+ req.setTimeout(this._socketTimeout || 3 * 60000, () => {
+ if (socket) {
+ socket.end();
+ }
+ handleResult(new Error(`Request timeout: ${info.options.path}`));
+ });
+ req.on('error', function (err) {
+ // err has statusCode property
+ // res should have headers
+ handleResult(err);
+ });
+ if (data && typeof data === 'string') {
+ req.write(data, 'utf8');
+ }
+ if (data && typeof data !== 'string') {
+ data.on('close', function () {
+ req.end();
+ });
+ data.pipe(req);
+ }
+ else {
+ req.end();
+ }
+ }
+ /**
+ * Gets an http agent. This function is useful when you need an http agent that handles
+ * routing through a proxy server - depending upon the url and proxy environment variables.
+ * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
+ */
+ getAgent(serverUrl) {
+ const parsedUrl = new URL(serverUrl);
+ return this._getAgent(parsedUrl);
+ }
+ _prepareRequest(method, requestUrl, headers) {
+ const info = {};
+ info.parsedUrl = requestUrl;
+ const usingSsl = info.parsedUrl.protocol === 'https:';
+ info.httpModule = usingSsl ? https : http;
+ const defaultPort = usingSsl ? 443 : 80;
+ info.options = {};
+ info.options.host = info.parsedUrl.hostname;
+ info.options.port = info.parsedUrl.port
+ ? parseInt(info.parsedUrl.port)
+ : defaultPort;
+ info.options.path =
+ (info.parsedUrl.pathname || '') + (info.parsedUrl.search || '');
+ info.options.method = method;
+ info.options.headers = this._mergeHeaders(headers);
+ if (this.userAgent != null) {
+ info.options.headers['user-agent'] = this.userAgent;
+ }
+ info.options.agent = this._getAgent(info.parsedUrl);
+ // gives handlers an opportunity to participate
+ if (this.handlers) {
+ for (const handler of this.handlers) {
+ handler.prepareRequest(info.options);
+ }
+ }
+ return info;
+ }
+ _mergeHeaders(headers) {
+ if (this.requestOptions && this.requestOptions.headers) {
+ return Object.assign({}, lowercaseKeys(this.requestOptions.headers), lowercaseKeys(headers || {}));
+ }
+ return lowercaseKeys(headers || {});
+ }
+ _getExistingOrDefaultHeader(additionalHeaders, header, _default) {
+ let clientHeader;
+ if (this.requestOptions && this.requestOptions.headers) {
+ clientHeader = lowercaseKeys(this.requestOptions.headers)[header];
+ }
+ return additionalHeaders[header] || clientHeader || _default;
+ }
+ _getAgent(parsedUrl) {
+ let agent;
+ const proxyUrl = pm.getProxyUrl(parsedUrl);
+ const useProxy = proxyUrl && proxyUrl.hostname;
+ if (this._keepAlive && useProxy) {
+ agent = this._proxyAgent;
+ }
+ if (this._keepAlive && !useProxy) {
+ agent = this._agent;
+ }
+ // if agent is already assigned use that agent.
+ if (agent) {
+ return agent;
+ }
+ const usingSsl = parsedUrl.protocol === 'https:';
+ let maxSockets = 100;
+ if (this.requestOptions) {
+ maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets;
+ }
+ // This is `useProxy` again, but we need to check `proxyURl` directly for TypeScripts's flow analysis.
+ if (proxyUrl && proxyUrl.hostname) {
+ const agentOptions = {
+ maxSockets,
+ keepAlive: this._keepAlive,
+ proxy: Object.assign(Object.assign({}, ((proxyUrl.username || proxyUrl.password) && {
+ proxyAuth: `${proxyUrl.username}:${proxyUrl.password}`
+ })), { host: proxyUrl.hostname, port: proxyUrl.port })
+ };
+ let tunnelAgent;
+ const overHttps = proxyUrl.protocol === 'https:';
+ if (usingSsl) {
+ tunnelAgent = overHttps ? tunnel.httpsOverHttps : tunnel.httpsOverHttp;
+ }
+ else {
+ tunnelAgent = overHttps ? tunnel.httpOverHttps : tunnel.httpOverHttp;
+ }
+ agent = tunnelAgent(agentOptions);
+ this._proxyAgent = agent;
+ }
+ // if reusing agent across request and tunneling agent isn't assigned create a new agent
+ if (this._keepAlive && !agent) {
+ const options = { keepAlive: this._keepAlive, maxSockets };
+ agent = usingSsl ? new https.Agent(options) : new http.Agent(options);
+ this._agent = agent;
+ }
+ // if not using private agent and tunnel agent isn't setup then use global agent
+ if (!agent) {
+ agent = usingSsl ? https.globalAgent : http.globalAgent;
+ }
+ if (usingSsl && this._ignoreSslError) {
+ // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process
+ // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options
+ // we have to cast it to any and change it directly
+ agent.options = Object.assign(agent.options || {}, {
+ rejectUnauthorized: false
+ });
+ }
+ return agent;
+ }
+ _performExponentialBackoff(retryNumber) {
+ return __awaiter(this, void 0, void 0, function* () {
+ retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber);
+ const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber);
+ return new Promise(resolve => setTimeout(() => resolve(), ms));
+ });
+ }
+ _processResponse(res, options) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
+ const statusCode = res.message.statusCode || 0;
+ const response = {
+ statusCode,
+ result: null,
+ headers: {}
+ };
+ // not found leads to null obj returned
+ if (statusCode === HttpCodes.NotFound) {
+ resolve(response);
+ }
+ // get the result from the body
+ function dateTimeDeserializer(key, value) {
+ if (typeof value === 'string') {
+ const a = new Date(value);
+ if (!isNaN(a.valueOf())) {
+ return a;
+ }
+ }
+ return value;
+ }
+ let obj;
+ let contents;
+ try {
+ contents = yield res.readBody();
+ if (contents && contents.length > 0) {
+ if (options && options.deserializeDates) {
+ obj = JSON.parse(contents, dateTimeDeserializer);
+ }
+ else {
+ obj = JSON.parse(contents);
+ }
+ response.result = obj;
+ }
+ response.headers = res.message.headers;
+ }
+ catch (err) {
+ // Invalid resource (contents not json); leaving result obj null
+ }
+ // note that 3xx redirects are handled by the http layer.
+ if (statusCode > 299) {
+ let msg;
+ // if exception/error in body, attempt to get better error
+ if (obj && obj.message) {
+ msg = obj.message;
+ }
+ else if (contents && contents.length > 0) {
+ // it may be the case that the exception is in the body message as string
+ msg = contents;
+ }
+ else {
+ msg = `Failed request: (${statusCode})`;
+ }
+ const err = new HttpClientError(msg, statusCode);
+ err.result = response.result;
+ reject(err);
+ }
+ else {
+ resolve(response);
+ }
+ }));
+ });
+ }
+}
+exports.HttpClient = HttpClient;
+const lowercaseKeys = (obj) => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
+//# sourceMappingURL=index.js.map
+
+/***/ }),
+
+/***/ 4977:
+/***/ ((__unused_webpack_module, exports) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.checkBypass = exports.getProxyUrl = void 0;
+function getProxyUrl(reqUrl) {
+ const usingSsl = reqUrl.protocol === 'https:';
+ if (checkBypass(reqUrl)) {
+ return undefined;
+ }
+ const proxyVar = (() => {
+ if (usingSsl) {
+ return process.env['https_proxy'] || process.env['HTTPS_PROXY'];
+ }
+ else {
+ return process.env['http_proxy'] || process.env['HTTP_PROXY'];
+ }
+ })();
+ if (proxyVar) {
+ return new URL(proxyVar);
+ }
+ else {
+ return undefined;
+ }
+}
+exports.getProxyUrl = getProxyUrl;
+function checkBypass(reqUrl) {
+ if (!reqUrl.hostname) {
+ return false;
+ }
+ const noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || '';
+ if (!noProxy) {
+ return false;
+ }
+ // Determine the request port
+ let reqPort;
+ if (reqUrl.port) {
+ reqPort = Number(reqUrl.port);
+ }
+ else if (reqUrl.protocol === 'http:') {
+ reqPort = 80;
+ }
+ else if (reqUrl.protocol === 'https:') {
+ reqPort = 443;
+ }
+ // Format the request hostname and hostname with port
+ const upperReqHosts = [reqUrl.hostname.toUpperCase()];
+ if (typeof reqPort === 'number') {
+ upperReqHosts.push(`${upperReqHosts[0]}:${reqPort}`);
+ }
+ // Compare request host against noproxy
+ for (const upperNoProxyItem of noProxy
+ .split(',')
+ .map(x => x.trim().toUpperCase())
+ .filter(x => x)) {
+ if (upperReqHosts.some(x => x === upperNoProxyItem)) {
+ return true;
+ }
+ }
+ return false;
+}
+exports.checkBypass = checkBypass;
+//# sourceMappingURL=proxy.js.map
+
+/***/ }),
+
/***/ 3771:
/***/ ((module, exports) => {
diff --git a/dist/setup/index.js b/dist/setup/index.js
index b98b9af2..f1c0ac3a 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -90,17 +90,18 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
checkKey(key);
}
const compressionMethod = yield utils.getCompressionMethod();
- // path are needed to compute version
- const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
- compressionMethod
- });
- if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
- // Cache not found
- return undefined;
- }
- const archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
- core.debug(`Archive Path: ${archivePath}`);
+ let archivePath = '';
try {
+ // path are needed to compute version
+ const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
+ compressionMethod
+ });
+ if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
+ // Cache not found
+ return undefined;
+ }
+ archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
+ core.debug(`Archive Path: ${archivePath}`);
// Download the cache from the cache entry
yield cacheHttpClient.downloadCache(cacheEntry.archiveLocation, archivePath, options);
if (core.isDebug()) {
@@ -110,6 +111,17 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
core.info(`Cache Size: ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B)`);
yield tar_1.extractTar(archivePath, compressionMethod);
core.info('Cache restored successfully');
+ return cacheEntry.cacheKey;
+ }
+ catch (error) {
+ const typedError = error;
+ if (typedError.name === ValidationError.name) {
+ throw error;
+ }
+ else {
+ // Supress all non-validation cache related errors because caching should be optional
+ core.warning(`Failed to restore: ${error.message}`);
+ }
}
finally {
// Try to delete the archive to save space
@@ -120,7 +132,7 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
core.debug(`Failed to delete archive: ${error}`);
}
}
- return cacheEntry.cacheKey;
+ return undefined;
});
}
exports.restoreCache = restoreCache;
@@ -138,10 +150,13 @@ function saveCache(paths, key, options) {
checkPaths(paths);
checkKey(key);
const compressionMethod = yield utils.getCompressionMethod();
- let cacheId = null;
+ let cacheId = -1;
const cachePaths = yield utils.resolvePaths(paths);
core.debug('Cache Paths:');
core.debug(`${JSON.stringify(cachePaths)}`);
+ if (cachePaths.length === 0) {
+ throw new Error(`Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.`);
+ }
const archiveFolder = yield utils.createTempDirectory();
const archivePath = path.join(archiveFolder, utils.getCacheFileName(compressionMethod));
core.debug(`Archive Path: ${archivePath}`);
@@ -174,6 +189,18 @@ function saveCache(paths, key, options) {
core.debug(`Saving Cache (ID: ${cacheId})`);
yield cacheHttpClient.saveCache(cacheId, archivePath, options);
}
+ catch (error) {
+ const typedError = error;
+ if (typedError.name === ValidationError.name) {
+ throw error;
+ }
+ else if (typedError.name === ReserveCacheError.name) {
+ core.info(`Failed to save: ${typedError.message}`);
+ }
+ else {
+ core.warning(`Failed to save: ${typedError.message}`);
+ }
+ }
finally {
// Try to delete the archive to save space
try {
@@ -214,8 +241,8 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(9925);
-const auth_1 = __nccwpck_require__(3702);
+const http_client_1 = __nccwpck_require__(1825);
+const auth_1 = __nccwpck_require__(2001);
const crypto = __importStar(__nccwpck_require__(6113));
const fs = __importStar(__nccwpck_require__(7147));
const url_1 = __nccwpck_require__(7310);
@@ -647,7 +674,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(9925);
+const http_client_1 = __nccwpck_require__(1825);
const storage_blob_1 = __nccwpck_require__(4100);
const buffer = __importStar(__nccwpck_require__(4300));
const fs = __importStar(__nccwpck_require__(7147));
@@ -885,7 +912,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
-const http_client_1 = __nccwpck_require__(9925);
+const http_client_1 = __nccwpck_require__(1825);
const constants_1 = __nccwpck_require__(8840);
function isSuccessStatusCode(statusCode) {
if (!statusCode) {
@@ -962,7 +989,7 @@ function retryTypedResponse(name, method, maxAttempts = constants_1.DefaultRetry
return __awaiter(this, void 0, void 0, function* () {
return yield retry(name, method, (response) => response.statusCode, maxAttempts, delay,
// If the error object contains the statusCode property, extract it and return
- // an ITypedResponse so it can be processed by the retry logic.
+ // an TypedResponse so it can be processed by the retry logic.
(error) => {
if (error instanceof http_client_1.HttpClientError) {
return {
@@ -1120,6 +1147,8 @@ function createTar(archiveFolder, sourceDirectories, compressionMethod) {
...getCompressionProgram(),
'-cf',
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
+ '--exclude',
+ cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'-P',
'-C',
workingDirectory.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
@@ -2292,6 +2321,774 @@ exports.SearchState = SearchState;
/***/ }),
+/***/ 2001:
+/***/ (function(__unused_webpack_module, exports) {
+
+"use strict";
+
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.PersonalAccessTokenCredentialHandler = exports.BearerCredentialHandler = exports.BasicCredentialHandler = void 0;
+class BasicCredentialHandler {
+ constructor(username, password) {
+ this.username = username;
+ this.password = password;
+ }
+ prepareRequest(options) {
+ if (!options.headers) {
+ throw Error('The request has no headers');
+ }
+ options.headers['Authorization'] = `Basic ${Buffer.from(`${this.username}:${this.password}`).toString('base64')}`;
+ }
+ // This handler cannot handle 401
+ canHandleAuthentication() {
+ return false;
+ }
+ handleAuthentication() {
+ return __awaiter(this, void 0, void 0, function* () {
+ throw new Error('not implemented');
+ });
+ }
+}
+exports.BasicCredentialHandler = BasicCredentialHandler;
+class BearerCredentialHandler {
+ constructor(token) {
+ this.token = token;
+ }
+ // currently implements pre-authorization
+ // TODO: support preAuth = false where it hooks on 401
+ prepareRequest(options) {
+ if (!options.headers) {
+ throw Error('The request has no headers');
+ }
+ options.headers['Authorization'] = `Bearer ${this.token}`;
+ }
+ // This handler cannot handle 401
+ canHandleAuthentication() {
+ return false;
+ }
+ handleAuthentication() {
+ return __awaiter(this, void 0, void 0, function* () {
+ throw new Error('not implemented');
+ });
+ }
+}
+exports.BearerCredentialHandler = BearerCredentialHandler;
+class PersonalAccessTokenCredentialHandler {
+ constructor(token) {
+ this.token = token;
+ }
+ // currently implements pre-authorization
+ // TODO: support preAuth = false where it hooks on 401
+ prepareRequest(options) {
+ if (!options.headers) {
+ throw Error('The request has no headers');
+ }
+ options.headers['Authorization'] = `Basic ${Buffer.from(`PAT:${this.token}`).toString('base64')}`;
+ }
+ // This handler cannot handle 401
+ canHandleAuthentication() {
+ return false;
+ }
+ handleAuthentication() {
+ return __awaiter(this, void 0, void 0, function* () {
+ throw new Error('not implemented');
+ });
+ }
+}
+exports.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHandler;
+//# sourceMappingURL=auth.js.map
+
+/***/ }),
+
+/***/ 1825:
+/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
+
+"use strict";
+
+/* eslint-disable @typescript-eslint/no-explicit-any */
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.HttpClient = exports.isHttps = exports.HttpClientResponse = exports.HttpClientError = exports.getProxyUrl = exports.MediaTypes = exports.Headers = exports.HttpCodes = void 0;
+const http = __importStar(__nccwpck_require__(3685));
+const https = __importStar(__nccwpck_require__(5687));
+const pm = __importStar(__nccwpck_require__(4977));
+const tunnel = __importStar(__nccwpck_require__(4294));
+var HttpCodes;
+(function (HttpCodes) {
+ HttpCodes[HttpCodes["OK"] = 200] = "OK";
+ HttpCodes[HttpCodes["MultipleChoices"] = 300] = "MultipleChoices";
+ HttpCodes[HttpCodes["MovedPermanently"] = 301] = "MovedPermanently";
+ HttpCodes[HttpCodes["ResourceMoved"] = 302] = "ResourceMoved";
+ HttpCodes[HttpCodes["SeeOther"] = 303] = "SeeOther";
+ HttpCodes[HttpCodes["NotModified"] = 304] = "NotModified";
+ HttpCodes[HttpCodes["UseProxy"] = 305] = "UseProxy";
+ HttpCodes[HttpCodes["SwitchProxy"] = 306] = "SwitchProxy";
+ HttpCodes[HttpCodes["TemporaryRedirect"] = 307] = "TemporaryRedirect";
+ HttpCodes[HttpCodes["PermanentRedirect"] = 308] = "PermanentRedirect";
+ HttpCodes[HttpCodes["BadRequest"] = 400] = "BadRequest";
+ HttpCodes[HttpCodes["Unauthorized"] = 401] = "Unauthorized";
+ HttpCodes[HttpCodes["PaymentRequired"] = 402] = "PaymentRequired";
+ HttpCodes[HttpCodes["Forbidden"] = 403] = "Forbidden";
+ HttpCodes[HttpCodes["NotFound"] = 404] = "NotFound";
+ HttpCodes[HttpCodes["MethodNotAllowed"] = 405] = "MethodNotAllowed";
+ HttpCodes[HttpCodes["NotAcceptable"] = 406] = "NotAcceptable";
+ HttpCodes[HttpCodes["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
+ HttpCodes[HttpCodes["RequestTimeout"] = 408] = "RequestTimeout";
+ HttpCodes[HttpCodes["Conflict"] = 409] = "Conflict";
+ HttpCodes[HttpCodes["Gone"] = 410] = "Gone";
+ HttpCodes[HttpCodes["TooManyRequests"] = 429] = "TooManyRequests";
+ HttpCodes[HttpCodes["InternalServerError"] = 500] = "InternalServerError";
+ HttpCodes[HttpCodes["NotImplemented"] = 501] = "NotImplemented";
+ HttpCodes[HttpCodes["BadGateway"] = 502] = "BadGateway";
+ HttpCodes[HttpCodes["ServiceUnavailable"] = 503] = "ServiceUnavailable";
+ HttpCodes[HttpCodes["GatewayTimeout"] = 504] = "GatewayTimeout";
+})(HttpCodes = exports.HttpCodes || (exports.HttpCodes = {}));
+var Headers;
+(function (Headers) {
+ Headers["Accept"] = "accept";
+ Headers["ContentType"] = "content-type";
+})(Headers = exports.Headers || (exports.Headers = {}));
+var MediaTypes;
+(function (MediaTypes) {
+ MediaTypes["ApplicationJson"] = "application/json";
+})(MediaTypes = exports.MediaTypes || (exports.MediaTypes = {}));
+/**
+ * Returns the proxy URL, depending upon the supplied url and proxy environment variables.
+ * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
+ */
+function getProxyUrl(serverUrl) {
+ const proxyUrl = pm.getProxyUrl(new URL(serverUrl));
+ return proxyUrl ? proxyUrl.href : '';
+}
+exports.getProxyUrl = getProxyUrl;
+const HttpRedirectCodes = [
+ HttpCodes.MovedPermanently,
+ HttpCodes.ResourceMoved,
+ HttpCodes.SeeOther,
+ HttpCodes.TemporaryRedirect,
+ HttpCodes.PermanentRedirect
+];
+const HttpResponseRetryCodes = [
+ HttpCodes.BadGateway,
+ HttpCodes.ServiceUnavailable,
+ HttpCodes.GatewayTimeout
+];
+const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD'];
+const ExponentialBackoffCeiling = 10;
+const ExponentialBackoffTimeSlice = 5;
+class HttpClientError extends Error {
+ constructor(message, statusCode) {
+ super(message);
+ this.name = 'HttpClientError';
+ this.statusCode = statusCode;
+ Object.setPrototypeOf(this, HttpClientError.prototype);
+ }
+}
+exports.HttpClientError = HttpClientError;
+class HttpClientResponse {
+ constructor(message) {
+ this.message = message;
+ }
+ readBody() {
+ return __awaiter(this, void 0, void 0, function* () {
+ return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
+ let output = Buffer.alloc(0);
+ this.message.on('data', (chunk) => {
+ output = Buffer.concat([output, chunk]);
+ });
+ this.message.on('end', () => {
+ resolve(output.toString());
+ });
+ }));
+ });
+ }
+}
+exports.HttpClientResponse = HttpClientResponse;
+function isHttps(requestUrl) {
+ const parsedUrl = new URL(requestUrl);
+ return parsedUrl.protocol === 'https:';
+}
+exports.isHttps = isHttps;
+class HttpClient {
+ constructor(userAgent, handlers, requestOptions) {
+ this._ignoreSslError = false;
+ this._allowRedirects = true;
+ this._allowRedirectDowngrade = false;
+ this._maxRedirects = 50;
+ this._allowRetries = false;
+ this._maxRetries = 1;
+ this._keepAlive = false;
+ this._disposed = false;
+ this.userAgent = userAgent;
+ this.handlers = handlers || [];
+ this.requestOptions = requestOptions;
+ if (requestOptions) {
+ if (requestOptions.ignoreSslError != null) {
+ this._ignoreSslError = requestOptions.ignoreSslError;
+ }
+ this._socketTimeout = requestOptions.socketTimeout;
+ if (requestOptions.allowRedirects != null) {
+ this._allowRedirects = requestOptions.allowRedirects;
+ }
+ if (requestOptions.allowRedirectDowngrade != null) {
+ this._allowRedirectDowngrade = requestOptions.allowRedirectDowngrade;
+ }
+ if (requestOptions.maxRedirects != null) {
+ this._maxRedirects = Math.max(requestOptions.maxRedirects, 0);
+ }
+ if (requestOptions.keepAlive != null) {
+ this._keepAlive = requestOptions.keepAlive;
+ }
+ if (requestOptions.allowRetries != null) {
+ this._allowRetries = requestOptions.allowRetries;
+ }
+ if (requestOptions.maxRetries != null) {
+ this._maxRetries = requestOptions.maxRetries;
+ }
+ }
+ }
+ options(requestUrl, additionalHeaders) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('OPTIONS', requestUrl, null, additionalHeaders || {});
+ });
+ }
+ get(requestUrl, additionalHeaders) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('GET', requestUrl, null, additionalHeaders || {});
+ });
+ }
+ del(requestUrl, additionalHeaders) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('DELETE', requestUrl, null, additionalHeaders || {});
+ });
+ }
+ post(requestUrl, data, additionalHeaders) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('POST', requestUrl, data, additionalHeaders || {});
+ });
+ }
+ patch(requestUrl, data, additionalHeaders) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('PATCH', requestUrl, data, additionalHeaders || {});
+ });
+ }
+ put(requestUrl, data, additionalHeaders) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('PUT', requestUrl, data, additionalHeaders || {});
+ });
+ }
+ head(requestUrl, additionalHeaders) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request('HEAD', requestUrl, null, additionalHeaders || {});
+ });
+ }
+ sendStream(verb, requestUrl, stream, additionalHeaders) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.request(verb, requestUrl, stream, additionalHeaders);
+ });
+ }
+ /**
+ * Gets a typed object from an endpoint
+ * Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise
+ */
+ getJson(requestUrl, additionalHeaders = {}) {
+ return __awaiter(this, void 0, void 0, function* () {
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ const res = yield this.get(requestUrl, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ });
+ }
+ postJson(requestUrl, obj, additionalHeaders = {}) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const data = JSON.stringify(obj, null, 2);
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
+ const res = yield this.post(requestUrl, data, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ });
+ }
+ putJson(requestUrl, obj, additionalHeaders = {}) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const data = JSON.stringify(obj, null, 2);
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
+ const res = yield this.put(requestUrl, data, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ });
+ }
+ patchJson(requestUrl, obj, additionalHeaders = {}) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const data = JSON.stringify(obj, null, 2);
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
+ additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
+ const res = yield this.patch(requestUrl, data, additionalHeaders);
+ return this._processResponse(res, this.requestOptions);
+ });
+ }
+ /**
+ * Makes a raw http request.
+ * All other methods such as get, post, patch, and request ultimately call this.
+ * Prefer get, del, post and patch
+ */
+ request(verb, requestUrl, data, headers) {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (this._disposed) {
+ throw new Error('Client has already been disposed.');
+ }
+ const parsedUrl = new URL(requestUrl);
+ let info = this._prepareRequest(verb, parsedUrl, headers);
+ // Only perform retries on reads since writes may not be idempotent.
+ const maxTries = this._allowRetries && RetryableHttpVerbs.includes(verb)
+ ? this._maxRetries + 1
+ : 1;
+ let numTries = 0;
+ let response;
+ do {
+ response = yield this.requestRaw(info, data);
+ // Check if it's an authentication challenge
+ if (response &&
+ response.message &&
+ response.message.statusCode === HttpCodes.Unauthorized) {
+ let authenticationHandler;
+ for (const handler of this.handlers) {
+ if (handler.canHandleAuthentication(response)) {
+ authenticationHandler = handler;
+ break;
+ }
+ }
+ if (authenticationHandler) {
+ return authenticationHandler.handleAuthentication(this, info, data);
+ }
+ else {
+ // We have received an unauthorized response but have no handlers to handle it.
+ // Let the response return to the caller.
+ return response;
+ }
+ }
+ let redirectsRemaining = this._maxRedirects;
+ while (response.message.statusCode &&
+ HttpRedirectCodes.includes(response.message.statusCode) &&
+ this._allowRedirects &&
+ redirectsRemaining > 0) {
+ const redirectUrl = response.message.headers['location'];
+ if (!redirectUrl) {
+ // if there's no location to redirect to, we won't
+ break;
+ }
+ const parsedRedirectUrl = new URL(redirectUrl);
+ if (parsedUrl.protocol === 'https:' &&
+ parsedUrl.protocol !== parsedRedirectUrl.protocol &&
+ !this._allowRedirectDowngrade) {
+ throw new Error('Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.');
+ }
+ // we need to finish reading the response before reassigning response
+ // which will leak the open socket.
+ yield response.readBody();
+ // strip authorization header if redirected to a different hostname
+ if (parsedRedirectUrl.hostname !== parsedUrl.hostname) {
+ for (const header in headers) {
+ // header names are case insensitive
+ if (header.toLowerCase() === 'authorization') {
+ delete headers[header];
+ }
+ }
+ }
+ // let's make the request with the new redirectUrl
+ info = this._prepareRequest(verb, parsedRedirectUrl, headers);
+ response = yield this.requestRaw(info, data);
+ redirectsRemaining--;
+ }
+ if (!response.message.statusCode ||
+ !HttpResponseRetryCodes.includes(response.message.statusCode)) {
+ // If not a retry code, return immediately instead of retrying
+ return response;
+ }
+ numTries += 1;
+ if (numTries < maxTries) {
+ yield response.readBody();
+ yield this._performExponentialBackoff(numTries);
+ }
+ } while (numTries < maxTries);
+ return response;
+ });
+ }
+ /**
+ * Needs to be called if keepAlive is set to true in request options.
+ */
+ dispose() {
+ if (this._agent) {
+ this._agent.destroy();
+ }
+ this._disposed = true;
+ }
+ /**
+ * Raw request.
+ * @param info
+ * @param data
+ */
+ requestRaw(info, data) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return new Promise((resolve, reject) => {
+ function callbackForResult(err, res) {
+ if (err) {
+ reject(err);
+ }
+ else if (!res) {
+ // If `err` is not passed, then `res` must be passed.
+ reject(new Error('Unknown error'));
+ }
+ else {
+ resolve(res);
+ }
+ }
+ this.requestRawWithCallback(info, data, callbackForResult);
+ });
+ });
+ }
+ /**
+ * Raw request with callback.
+ * @param info
+ * @param data
+ * @param onResult
+ */
+ requestRawWithCallback(info, data, onResult) {
+ if (typeof data === 'string') {
+ if (!info.options.headers) {
+ info.options.headers = {};
+ }
+ info.options.headers['Content-Length'] = Buffer.byteLength(data, 'utf8');
+ }
+ let callbackCalled = false;
+ function handleResult(err, res) {
+ if (!callbackCalled) {
+ callbackCalled = true;
+ onResult(err, res);
+ }
+ }
+ const req = info.httpModule.request(info.options, (msg) => {
+ const res = new HttpClientResponse(msg);
+ handleResult(undefined, res);
+ });
+ let socket;
+ req.on('socket', sock => {
+ socket = sock;
+ });
+ // If we ever get disconnected, we want the socket to timeout eventually
+ req.setTimeout(this._socketTimeout || 3 * 60000, () => {
+ if (socket) {
+ socket.end();
+ }
+ handleResult(new Error(`Request timeout: ${info.options.path}`));
+ });
+ req.on('error', function (err) {
+ // err has statusCode property
+ // res should have headers
+ handleResult(err);
+ });
+ if (data && typeof data === 'string') {
+ req.write(data, 'utf8');
+ }
+ if (data && typeof data !== 'string') {
+ data.on('close', function () {
+ req.end();
+ });
+ data.pipe(req);
+ }
+ else {
+ req.end();
+ }
+ }
+ /**
+ * Gets an http agent. This function is useful when you need an http agent that handles
+ * routing through a proxy server - depending upon the url and proxy environment variables.
+ * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
+ */
+ getAgent(serverUrl) {
+ const parsedUrl = new URL(serverUrl);
+ return this._getAgent(parsedUrl);
+ }
+ _prepareRequest(method, requestUrl, headers) {
+ const info = {};
+ info.parsedUrl = requestUrl;
+ const usingSsl = info.parsedUrl.protocol === 'https:';
+ info.httpModule = usingSsl ? https : http;
+ const defaultPort = usingSsl ? 443 : 80;
+ info.options = {};
+ info.options.host = info.parsedUrl.hostname;
+ info.options.port = info.parsedUrl.port
+ ? parseInt(info.parsedUrl.port)
+ : defaultPort;
+ info.options.path =
+ (info.parsedUrl.pathname || '') + (info.parsedUrl.search || '');
+ info.options.method = method;
+ info.options.headers = this._mergeHeaders(headers);
+ if (this.userAgent != null) {
+ info.options.headers['user-agent'] = this.userAgent;
+ }
+ info.options.agent = this._getAgent(info.parsedUrl);
+ // gives handlers an opportunity to participate
+ if (this.handlers) {
+ for (const handler of this.handlers) {
+ handler.prepareRequest(info.options);
+ }
+ }
+ return info;
+ }
+ _mergeHeaders(headers) {
+ if (this.requestOptions && this.requestOptions.headers) {
+ return Object.assign({}, lowercaseKeys(this.requestOptions.headers), lowercaseKeys(headers || {}));
+ }
+ return lowercaseKeys(headers || {});
+ }
+ _getExistingOrDefaultHeader(additionalHeaders, header, _default) {
+ let clientHeader;
+ if (this.requestOptions && this.requestOptions.headers) {
+ clientHeader = lowercaseKeys(this.requestOptions.headers)[header];
+ }
+ return additionalHeaders[header] || clientHeader || _default;
+ }
+ _getAgent(parsedUrl) {
+ let agent;
+ const proxyUrl = pm.getProxyUrl(parsedUrl);
+ const useProxy = proxyUrl && proxyUrl.hostname;
+ if (this._keepAlive && useProxy) {
+ agent = this._proxyAgent;
+ }
+ if (this._keepAlive && !useProxy) {
+ agent = this._agent;
+ }
+ // if agent is already assigned use that agent.
+ if (agent) {
+ return agent;
+ }
+ const usingSsl = parsedUrl.protocol === 'https:';
+ let maxSockets = 100;
+ if (this.requestOptions) {
+ maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets;
+ }
+ // This is `useProxy` again, but we need to check `proxyURl` directly for TypeScripts's flow analysis.
+ if (proxyUrl && proxyUrl.hostname) {
+ const agentOptions = {
+ maxSockets,
+ keepAlive: this._keepAlive,
+ proxy: Object.assign(Object.assign({}, ((proxyUrl.username || proxyUrl.password) && {
+ proxyAuth: `${proxyUrl.username}:${proxyUrl.password}`
+ })), { host: proxyUrl.hostname, port: proxyUrl.port })
+ };
+ let tunnelAgent;
+ const overHttps = proxyUrl.protocol === 'https:';
+ if (usingSsl) {
+ tunnelAgent = overHttps ? tunnel.httpsOverHttps : tunnel.httpsOverHttp;
+ }
+ else {
+ tunnelAgent = overHttps ? tunnel.httpOverHttps : tunnel.httpOverHttp;
+ }
+ agent = tunnelAgent(agentOptions);
+ this._proxyAgent = agent;
+ }
+ // if reusing agent across request and tunneling agent isn't assigned create a new agent
+ if (this._keepAlive && !agent) {
+ const options = { keepAlive: this._keepAlive, maxSockets };
+ agent = usingSsl ? new https.Agent(options) : new http.Agent(options);
+ this._agent = agent;
+ }
+ // if not using private agent and tunnel agent isn't setup then use global agent
+ if (!agent) {
+ agent = usingSsl ? https.globalAgent : http.globalAgent;
+ }
+ if (usingSsl && this._ignoreSslError) {
+ // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process
+ // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options
+ // we have to cast it to any and change it directly
+ agent.options = Object.assign(agent.options || {}, {
+ rejectUnauthorized: false
+ });
+ }
+ return agent;
+ }
+ _performExponentialBackoff(retryNumber) {
+ return __awaiter(this, void 0, void 0, function* () {
+ retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber);
+ const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber);
+ return new Promise(resolve => setTimeout(() => resolve(), ms));
+ });
+ }
+ _processResponse(res, options) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
+ const statusCode = res.message.statusCode || 0;
+ const response = {
+ statusCode,
+ result: null,
+ headers: {}
+ };
+ // not found leads to null obj returned
+ if (statusCode === HttpCodes.NotFound) {
+ resolve(response);
+ }
+ // get the result from the body
+ function dateTimeDeserializer(key, value) {
+ if (typeof value === 'string') {
+ const a = new Date(value);
+ if (!isNaN(a.valueOf())) {
+ return a;
+ }
+ }
+ return value;
+ }
+ let obj;
+ let contents;
+ try {
+ contents = yield res.readBody();
+ if (contents && contents.length > 0) {
+ if (options && options.deserializeDates) {
+ obj = JSON.parse(contents, dateTimeDeserializer);
+ }
+ else {
+ obj = JSON.parse(contents);
+ }
+ response.result = obj;
+ }
+ response.headers = res.message.headers;
+ }
+ catch (err) {
+ // Invalid resource (contents not json); leaving result obj null
+ }
+ // note that 3xx redirects are handled by the http layer.
+ if (statusCode > 299) {
+ let msg;
+ // if exception/error in body, attempt to get better error
+ if (obj && obj.message) {
+ msg = obj.message;
+ }
+ else if (contents && contents.length > 0) {
+ // it may be the case that the exception is in the body message as string
+ msg = contents;
+ }
+ else {
+ msg = `Failed request: (${statusCode})`;
+ }
+ const err = new HttpClientError(msg, statusCode);
+ err.result = response.result;
+ reject(err);
+ }
+ else {
+ resolve(response);
+ }
+ }));
+ });
+ }
+}
+exports.HttpClient = HttpClient;
+const lowercaseKeys = (obj) => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
+//# sourceMappingURL=index.js.map
+
+/***/ }),
+
+/***/ 4977:
+/***/ ((__unused_webpack_module, exports) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.checkBypass = exports.getProxyUrl = void 0;
+function getProxyUrl(reqUrl) {
+ const usingSsl = reqUrl.protocol === 'https:';
+ if (checkBypass(reqUrl)) {
+ return undefined;
+ }
+ const proxyVar = (() => {
+ if (usingSsl) {
+ return process.env['https_proxy'] || process.env['HTTPS_PROXY'];
+ }
+ else {
+ return process.env['http_proxy'] || process.env['HTTP_PROXY'];
+ }
+ })();
+ if (proxyVar) {
+ return new URL(proxyVar);
+ }
+ else {
+ return undefined;
+ }
+}
+exports.getProxyUrl = getProxyUrl;
+function checkBypass(reqUrl) {
+ if (!reqUrl.hostname) {
+ return false;
+ }
+ const noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || '';
+ if (!noProxy) {
+ return false;
+ }
+ // Determine the request port
+ let reqPort;
+ if (reqUrl.port) {
+ reqPort = Number(reqUrl.port);
+ }
+ else if (reqUrl.protocol === 'http:') {
+ reqPort = 80;
+ }
+ else if (reqUrl.protocol === 'https:') {
+ reqPort = 443;
+ }
+ // Format the request hostname and hostname with port
+ const upperReqHosts = [reqUrl.hostname.toUpperCase()];
+ if (typeof reqPort === 'number') {
+ upperReqHosts.push(`${upperReqHosts[0]}:${reqPort}`);
+ }
+ // Compare request host against noproxy
+ for (const upperNoProxyItem of noProxy
+ .split(',')
+ .map(x => x.trim().toUpperCase())
+ .filter(x => x)) {
+ if (upperReqHosts.some(x => x === upperNoProxyItem)) {
+ return true;
+ }
+ }
+ return false;
+}
+exports.checkBypass = checkBypass;
+//# sourceMappingURL=proxy.js.map
+
+/***/ }),
+
/***/ 3771:
/***/ ((module, exports) => {
From 56f6060254e1c762cbbe5d69d3831ab68d2ee2ac Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Thu, 30 Jun 2022 14:41:09 +0200
Subject: [PATCH 23/77] Fix naming
---
src/setup-python.ts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/setup-python.ts b/src/setup-python.ts
index 58ebd8d0..62cee96d 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -39,15 +39,15 @@ function resolveVersionInput(): string {
if (versionFile) {
const defaultVersionFile = '.python-version';
- const VersionFileExists = fs.existsSync(versionFile);
+ const versionFileExists = fs.existsSync(versionFile);
const defaultVersionFileExists = fs.existsSync(defaultVersionFile);
- if (!VersionFileExists && !defaultVersionFileExists) {
+ if (!versionFileExists && !defaultVersionFileExists) {
throw new Error(
`The specified python version file at: ${versionFile} does not exist and default ${defaultVersionFile} file isn't found`
);
}
- if (VersionFileExists) {
+ if (versionFileExists) {
version = fs.readFileSync(versionFile, 'utf8');
core.info(`Resolved ${versionFile} as ${version}`);
} else {
From 84087f5301387d405e78745351baf99179125d2b Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Thu, 30 Jun 2022 16:21:14 +0200
Subject: [PATCH 24/77] Rearrange logic
---
src/setup-python.ts | 30 +++++++++++++++++-------------
1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/src/setup-python.ts b/src/setup-python.ts
index 62cee96d..ec1fcd89 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -39,28 +39,32 @@ function resolveVersionInput(): string {
if (versionFile) {
const defaultVersionFile = '.python-version';
- const versionFileExists = fs.existsSync(versionFile);
- const defaultVersionFileExists = fs.existsSync(defaultVersionFile);
+ if (!fs.existsSync(versionFile)) {
+ if (versionFile === defaultVersionFile) {
+ throw new Error(
+ `The specified python version file at: ${versionFile} does not exist.`
+ );
+ }
- if (!versionFileExists && !defaultVersionFileExists) {
- throw new Error(
- `The specified python version file at: ${versionFile} does not exist and default ${defaultVersionFile} file isn't found`
- );
- }
- if (versionFileExists) {
- version = fs.readFileSync(versionFile, 'utf8');
- core.info(`Resolved ${versionFile} as ${version}`);
- } else {
- version = fs.readFileSync(defaultVersionFile, 'utf8');
- core.info(`Resolved ${defaultVersionFile} as ${version}`);
+ if (fs.existsSync(defaultVersionFile)) {
+ versionFile = defaultVersionFile;
+ } else {
+ throw new Error(
+ `The specified python version file at: ${versionFile} does not exist and default ${defaultVersionFile} file isn't found`
+ );
+ }
}
+ version = fs.readFileSync(versionFile, 'utf8');
+ core.info(`Resolved ${versionFile} as ${version}`);
+
return version;
}
core.warning(
"Neither 'python-version' nor 'python-version-file' inputs were supplied. "
);
+
return version;
}
From a6b01c4e407b1f7787010fb1e61a07c065555209 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Thu, 30 Jun 2022 16:22:51 +0200
Subject: [PATCH 25/77] Rebuild action with new changes
---
dist/setup/index.js | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 2b48b607..5ab9c899 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -65270,19 +65270,19 @@ function resolveVersionInput() {
}
if (versionFile) {
const defaultVersionFile = '.python-version';
- const VersionFileExists = fs_1.default.existsSync(versionFile);
- const defaultVersionFileExists = fs_1.default.existsSync(defaultVersionFile);
- if (!VersionFileExists && !defaultVersionFileExists) {
- throw new Error(`The specified python version file at: ${versionFile} does not exist and default ${defaultVersionFile} file isn't found`);
- }
- if (VersionFileExists) {
- version = fs_1.default.readFileSync(versionFile, 'utf8');
- core.info(`Resolved ${versionFile} as ${version}`);
- }
- else {
- version = fs_1.default.readFileSync(defaultVersionFile, 'utf8');
- core.info(`Resolved ${defaultVersionFile} as ${version}`);
+ if (!fs_1.default.existsSync(versionFile)) {
+ if (versionFile === defaultVersionFile) {
+ throw new Error(`The specified python version file at: ${versionFile} does not exist.`);
+ }
+ if (fs_1.default.existsSync(defaultVersionFile)) {
+ versionFile = defaultVersionFile;
+ }
+ else {
+ throw new Error(`The specified python version file at: ${versionFile} does not exist and default ${defaultVersionFile} file isn't found`);
+ }
}
+ version = fs_1.default.readFileSync(versionFile, 'utf8');
+ core.info(`Resolved ${versionFile} as ${version}`);
return version;
}
core.warning("Neither 'python-version' nor 'python-version-file' inputs were supplied. ");
From d97b6edda3da1f628f85b7105cb690790e86c149 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Thu, 30 Jun 2022 16:25:46 +0200
Subject: [PATCH 26/77] Fix typos
---
dist/setup/index.js | 6 +++---
src/setup-python.ts | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 5ab9c899..43d4cfbb 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -65263,7 +65263,7 @@ function resolveVersionInput() {
let version = core.getInput('python-version');
let versionFile = core.getInput('python-version-file');
if (version && versionFile) {
- core.warning('Both python-version and python-version-file inputs are specified, only python-version will be used');
+ core.warning('Both python-version and python-version-file inputs are specified, only python-version will be used.');
}
if (version) {
return version;
@@ -65278,14 +65278,14 @@ function resolveVersionInput() {
versionFile = defaultVersionFile;
}
else {
- throw new Error(`The specified python version file at: ${versionFile} does not exist and default ${defaultVersionFile} file isn't found`);
+ throw new Error(`The specified python version file at: ${versionFile} does not exist and default ${defaultVersionFile} file isn't found.`);
}
}
version = fs_1.default.readFileSync(versionFile, 'utf8');
core.info(`Resolved ${versionFile} as ${version}`);
return version;
}
- core.warning("Neither 'python-version' nor 'python-version-file' inputs were supplied. ");
+ core.warning("Neither 'python-version' nor 'python-version-file' inputs were supplied.");
return version;
}
function run() {
diff --git a/src/setup-python.ts b/src/setup-python.ts
index ec1fcd89..fea50e13 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -28,7 +28,7 @@ function resolveVersionInput(): string {
if (version && versionFile) {
core.warning(
- 'Both python-version and python-version-file inputs are specified, only python-version will be used'
+ 'Both python-version and python-version-file inputs are specified, only python-version will be used.'
);
}
@@ -50,7 +50,7 @@ function resolveVersionInput(): string {
versionFile = defaultVersionFile;
} else {
throw new Error(
- `The specified python version file at: ${versionFile} does not exist and default ${defaultVersionFile} file isn't found`
+ `The specified python version file at: ${versionFile} does not exist and default ${defaultVersionFile} file isn't found.`
);
}
}
@@ -62,7 +62,7 @@ function resolveVersionInput(): string {
}
core.warning(
- "Neither 'python-version' nor 'python-version-file' inputs were supplied. "
+ "Neither 'python-version' nor 'python-version-file' inputs were supplied."
);
return version;
From 82eddc4023a579965135122e83230730392b1064 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Thu, 30 Jun 2022 16:34:29 +0200
Subject: [PATCH 27/77] Add warning in case the versionFile isn't found
---
dist/setup/index.js | 1 +
src/setup-python.ts | 3 +++
2 files changed, 4 insertions(+)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 43d4cfbb..f4394233 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -65275,6 +65275,7 @@ function resolveVersionInput() {
throw new Error(`The specified python version file at: ${versionFile} does not exist.`);
}
if (fs_1.default.existsSync(defaultVersionFile)) {
+ core.warning(`The specified python version file at: ${versionFile} does not exist. Attempting to find ${defaultVersionFile} file.`);
versionFile = defaultVersionFile;
}
else {
diff --git a/src/setup-python.ts b/src/setup-python.ts
index fea50e13..c4db766f 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -47,6 +47,9 @@ function resolveVersionInput(): string {
}
if (fs.existsSync(defaultVersionFile)) {
+ core.warning(
+ `The specified python version file at: ${versionFile} does not exist. Attempting to find ${defaultVersionFile} file.`
+ );
versionFile = defaultVersionFile;
} else {
throw new Error(
From 5fbb8194072b461a0b699e47c3d444b39e33bb8a Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Thu, 30 Jun 2022 17:32:12 +0200
Subject: [PATCH 28/77] Optimize logic, rebuild action
---
dist/setup/index.js | 20 +++++++++++---------
src/setup-python.ts | 27 ++++++++++++---------------
2 files changed, 23 insertions(+), 24 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index f4394233..474ce59f 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -65241,6 +65241,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.logWarning = void 0;
const core = __importStar(__nccwpck_require__(2186));
const finder = __importStar(__nccwpck_require__(9996));
const finderPyPy = __importStar(__nccwpck_require__(4003));
@@ -65269,24 +65270,20 @@ function resolveVersionInput() {
return version;
}
if (versionFile) {
- const defaultVersionFile = '.python-version';
if (!fs_1.default.existsSync(versionFile)) {
- if (versionFile === defaultVersionFile) {
- throw new Error(`The specified python version file at: ${versionFile} does not exist.`);
- }
- if (fs_1.default.existsSync(defaultVersionFile)) {
- core.warning(`The specified python version file at: ${versionFile} does not exist. Attempting to find ${defaultVersionFile} file.`);
- versionFile = defaultVersionFile;
+ logWarning(`The specified python version file at: ${versionFile} does not exist. Attempting to find .python-version file.`);
+ if (!fs_1.default.existsSync('.python-version')) {
+ throw new Error(`The specified python version file at: ${versionFile} does not exist and default .python-version file isn't found.`);
}
else {
- throw new Error(`The specified python version file at: ${versionFile} does not exist and default ${defaultVersionFile} file isn't found.`);
+ versionFile = '.python-version';
}
}
version = fs_1.default.readFileSync(versionFile, 'utf8');
core.info(`Resolved ${versionFile} as ${version}`);
return version;
}
- core.warning("Neither 'python-version' nor 'python-version-file' inputs were supplied.");
+ logWarning("Neither 'python-version' nor 'python-version-file' inputs were supplied.");
return version;
}
function run() {
@@ -65331,6 +65328,11 @@ function run() {
}
});
}
+function logWarning(message) {
+ const warningPrefix = '[warning]';
+ core.info(`${warningPrefix}${message}`);
+}
+exports.logWarning = logWarning;
run();
diff --git a/src/setup-python.ts b/src/setup-python.ts
index c4db766f..22c407ba 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -37,24 +37,16 @@ function resolveVersionInput(): string {
}
if (versionFile) {
- const defaultVersionFile = '.python-version';
-
if (!fs.existsSync(versionFile)) {
- if (versionFile === defaultVersionFile) {
+ logWarning(
+ `The specified python version file at: ${versionFile} does not exist. Attempting to find .python-version file.`
+ );
+ if (!fs.existsSync('.python-version')) {
throw new Error(
- `The specified python version file at: ${versionFile} does not exist.`
+ `The specified python version file at: ${versionFile} does not exist and default .python-version file isn't found.`
);
- }
-
- if (fs.existsSync(defaultVersionFile)) {
- core.warning(
- `The specified python version file at: ${versionFile} does not exist. Attempting to find ${defaultVersionFile} file.`
- );
- versionFile = defaultVersionFile;
} else {
- throw new Error(
- `The specified python version file at: ${versionFile} does not exist and default ${defaultVersionFile} file isn't found.`
- );
+ versionFile = '.python-version';
}
}
@@ -64,7 +56,7 @@ function resolveVersionInput(): string {
return version;
}
- core.warning(
+ logWarning(
"Neither 'python-version' nor 'python-version-file' inputs were supplied."
);
@@ -124,4 +116,9 @@ async function run() {
}
}
+export function logWarning(message: string): void {
+ const warningPrefix = '[warning]';
+ core.info(`${warningPrefix}${message}`);
+}
+
run();
From ccb7da8ae999f3923ec3f9ed841e83fd0e332963 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Thu, 30 Jun 2022 18:28:17 +0200
Subject: [PATCH 29/77] Change warning handler to default
---
dist/setup/index.js | 2 +-
src/setup-python.ts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 474ce59f..078ff004 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -65283,7 +65283,7 @@ function resolveVersionInput() {
core.info(`Resolved ${versionFile} as ${version}`);
return version;
}
- logWarning("Neither 'python-version' nor 'python-version-file' inputs were supplied.");
+ core.warning("Neither 'python-version' nor 'python-version-file' inputs were supplied.");
return version;
}
function run() {
diff --git a/src/setup-python.ts b/src/setup-python.ts
index 22c407ba..f1171f92 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -56,7 +56,7 @@ function resolveVersionInput(): string {
return version;
}
- logWarning(
+ core.warning(
"Neither 'python-version' nor 'python-version-file' inputs were supplied."
);
From 099ed898be0c04ebc3fdcd7c440ad36781523a46 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Thu, 30 Jun 2022 18:42:04 +0200
Subject: [PATCH 30/77] Optimize code
---
dist/setup/index.js | 10 ++++------
src/setup-python.ts | 11 ++++-------
2 files changed, 8 insertions(+), 13 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 078ff004..9f8f0d51 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -65271,12 +65271,10 @@ function resolveVersionInput() {
}
if (versionFile) {
if (!fs_1.default.existsSync(versionFile)) {
- logWarning(`The specified python version file at: ${versionFile} does not exist. Attempting to find .python-version file.`);
- if (!fs_1.default.existsSync('.python-version')) {
- throw new Error(`The specified python version file at: ${versionFile} does not exist and default .python-version file isn't found.`);
- }
- else {
- versionFile = '.python-version';
+ logWarning(`The specified python version file at: ${versionFile} doesn't exist. Attempting to find .python-version file.`);
+ versionFile = '.python-version';
+ if (!fs_1.default.existsSync(versionFile)) {
+ throw new Error(`The ${versionFile} doesn't exist.`);
}
}
version = fs_1.default.readFileSync(versionFile, 'utf8');
diff --git a/src/setup-python.ts b/src/setup-python.ts
index f1171f92..55bf4971 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -39,14 +39,11 @@ function resolveVersionInput(): string {
if (versionFile) {
if (!fs.existsSync(versionFile)) {
logWarning(
- `The specified python version file at: ${versionFile} does not exist. Attempting to find .python-version file.`
+ `The specified python version file at: ${versionFile} doesn't exist. Attempting to find .python-version file.`
);
- if (!fs.existsSync('.python-version')) {
- throw new Error(
- `The specified python version file at: ${versionFile} does not exist and default .python-version file isn't found.`
- );
- } else {
- versionFile = '.python-version';
+ versionFile = '.python-version';
+ if (!fs.existsSync(versionFile)) {
+ throw new Error(`The ${versionFile} doesn't exist.`);
}
}
From 96f494e18c81869c9d5eef39102df0b23b2bc4f2 Mon Sep 17 00:00:00 2001
From: Sergey Dolin
Date: Fri, 1 Jul 2022 10:28:46 +0200
Subject: [PATCH 31/77] trigger checks
From 412091c1e06cd58dc0bacfdc5bcc07449ebd20c0 Mon Sep 17 00:00:00 2001
From: mayeut
Date: Sat, 2 Jul 2022 11:40:53 +0200
Subject: [PATCH 32/77] Fix tests for update-environment==false
---
__tests__/find-pypy.test.ts | 4 ++++
__tests__/finder.test.ts | 6 ++++--
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/__tests__/find-pypy.test.ts b/__tests__/find-pypy.test.ts
index 04a27cf3..3da9a226 100644
--- a/__tests__/find-pypy.test.ts
+++ b/__tests__/find-pypy.test.ts
@@ -151,8 +151,11 @@ describe('findPyPyVersion', () => {
let spyChmodSync: jest.SpyInstance;
let spyCoreAddPath: jest.SpyInstance;
let spyCoreExportVariable: jest.SpyInstance;
+ const env = process.env;
beforeEach(() => {
+ jest.resetModules();
+ process.env = {...env};
tcFind = jest.spyOn(tc, 'find');
tcFind.mockImplementation((tool: string, version: string) => {
const semverRange = new semver.Range(version);
@@ -214,6 +217,7 @@ describe('findPyPyVersion', () => {
jest.resetAllMocks();
jest.clearAllMocks();
jest.restoreAllMocks();
+ process.env = env;
});
it('found PyPy in toolcache', async () => {
diff --git a/__tests__/finder.test.ts b/__tests__/finder.test.ts
index cf07a234..3bd279f1 100644
--- a/__tests__/finder.test.ts
+++ b/__tests__/finder.test.ts
@@ -28,10 +28,12 @@ const manifestData = require('./data/versions-manifest.json');
describe('Finder tests', () => {
let spyCoreAddPath: jest.SpyInstance;
let spyCoreExportVariable: jest.SpyInstance;
+ const env = process.env;
beforeEach(() => {
+ jest.resetModules();
+ process.env = {...env};
spyCoreAddPath = jest.spyOn(core, 'addPath');
-
spyCoreExportVariable = jest.spyOn(core, 'exportVariable');
});
@@ -39,6 +41,7 @@ describe('Finder tests', () => {
jest.resetAllMocks();
jest.clearAllMocks();
jest.restoreAllMocks();
+ process.env = env;
});
it('Finds Python if it is installed', async () => {
@@ -66,7 +69,6 @@ describe('Finder tests', () => {
await finder.useCpythonVersion('3.x', 'x64', false);
expect(spyCoreAddPath).not.toHaveBeenCalled();
expect(spyCoreExportVariable).not.toHaveBeenCalled();
- expect(spyCoreExportVariable).not.toHaveBeenCalled();
});
it('Finds stable Python version if it is not installed, but exists in the manifest', async () => {
From 2c9de4ed413bf4466f2fde83041579ed45167427 Mon Sep 17 00:00:00 2001
From: mayeut
Date: Sat, 2 Jul 2022 11:50:26 +0200
Subject: [PATCH 33/77] Remove duplicate code introduced in #440
#440 duplicated a block of code outside of `if (updateEnvironment) {` condition. This was probably an oversight when merging `main` back on the PR branch. The tests should have seen that `core.exportVariable` was being called and should have failed.
---
dist/setup/index.js | 9 ---------
src/find-python.ts | 11 -----------
2 files changed, 20 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index f1c0ac3a..d58c75f3 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -64845,15 +64845,6 @@ function useCpythonVersion(version, architecture, updateEnvironment) {
`The list of all available versions can be found here: ${installer.MANIFEST_URL}`
].join(os.EOL));
}
- if (utils_1.IS_LINUX) {
- const libPath = process.env.LD_LIBRARY_PATH
- ? `:${process.env.LD_LIBRARY_PATH}`
- : '';
- const pyLibPath = path.join(installDir, 'lib');
- if (!libPath.split(':').includes(pyLibPath)) {
- core.exportVariable('LD_LIBRARY_PATH', pyLibPath + libPath);
- }
- }
const _binDir = binDir(installDir);
const binaryExtension = utils_1.IS_WINDOWS ? '.exe' : '';
const pythonPath = path.join(utils_1.IS_WINDOWS ? installDir : _binDir, `python${binaryExtension}`);
diff --git a/src/find-python.ts b/src/find-python.ts
index 8c085d61..e1add953 100644
--- a/src/find-python.ts
+++ b/src/find-python.ts
@@ -70,17 +70,6 @@ export async function useCpythonVersion(
);
}
- if (IS_LINUX) {
- const libPath = process.env.LD_LIBRARY_PATH
- ? `:${process.env.LD_LIBRARY_PATH}`
- : '';
- const pyLibPath = path.join(installDir, 'lib');
-
- if (!libPath.split(':').includes(pyLibPath)) {
- core.exportVariable('LD_LIBRARY_PATH', pyLibPath + libPath);
- }
- }
-
const _binDir = binDir(installDir);
const binaryExtension = IS_WINDOWS ? '.exe' : '';
const pythonPath = path.join(
From f4b85ae24e3deb0b31366c598a66e08bb4d4bc32 Mon Sep 17 00:00:00 2001
From: Sven Serlier <85389871+wrt54g@users.noreply.github.com>
Date: Sun, 3 Jul 2022 20:10:08 +0200
Subject: [PATCH 34/77] Update actions
---
.github/workflows/check-dist.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/check-dist.yml b/.github/workflows/check-dist.yml
index 4c3d69e2..6274fd28 100644
--- a/.github/workflows/check-dist.yml
+++ b/.github/workflows/check-dist.yml
@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Set Node.js 16.x
uses: actions/setup-node@v3
@@ -45,7 +45,7 @@ jobs:
id: diff
# If index.js was different than expected, upload the expected version as an artifact
- - uses: actions/upload-artifact@v2
+ - uses: actions/upload-artifact@v3
if: ${{ failure() && steps.diff.conclusion == 'failure' }}
with:
name: dist
From 5a1dd6b34d3ec33151c395cf8fc433629fdcc47c Mon Sep 17 00:00:00 2001
From: Sven Serlier <85389871+wrt54g@users.noreply.github.com>
Date: Sun, 3 Jul 2022 20:11:27 +0200
Subject: [PATCH 35/77] Update actions
---
.github/workflows/codeql-analysis.yml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index c30fab46..3ea240d8 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -18,11 +18,11 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v1
+ uses: github/codeql-action/init@v2
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java
@@ -30,7 +30,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
- uses: github/codeql-action/autobuild@v1
+ uses: github/codeql-action/autobuild@v2
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -44,4 +44,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v1
+ uses: github/codeql-action/analyze@v2
From 7d9c63da1be5117e942432dfba15cb5583b6f811 Mon Sep 17 00:00:00 2001
From: Sven Serlier <85389871+wrt54g@users.noreply.github.com>
Date: Sun, 3 Jul 2022 20:13:21 +0200
Subject: [PATCH 36/77] Update actions/checkout to v3
---
.github/workflows/licensed.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/licensed.yml b/.github/workflows/licensed.yml
index a78560b8..6f4cd922 100644
--- a/.github/workflows/licensed.yml
+++ b/.github/workflows/licensed.yml
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
name: Check licenses
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Set Node.js 16.x
uses: actions/setup-node@v3
with:
From d08a9d79f10546626afc655b2a5376f88e0126ff Mon Sep 17 00:00:00 2001
From: Sven Serlier <85389871+wrt54g@users.noreply.github.com>
Date: Sun, 3 Jul 2022 20:13:56 +0200
Subject: [PATCH 37/77] Update actions
---
.github/workflows/release-new-action-version.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/release-new-action-version.yml b/.github/workflows/release-new-action-version.yml
index 955ced7e..968c77fb 100644
--- a/.github/workflows/release-new-action-version.yml
+++ b/.github/workflows/release-new-action-version.yml
@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Update the ${{ env.TAG_NAME }} tag
- uses: actions/publish-action@v0.1.0
+ uses: actions/publish-action@v0.2.0
with:
source-tag: ${{ env.TAG_NAME }}
- slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
\ No newline at end of file
+ slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
From 4a7ca55b4090b249d2dbdb572c6bf83ca085ae44 Mon Sep 17 00:00:00 2001
From: Sven Serlier <85389871+wrt54g@users.noreply.github.com>
Date: Sun, 3 Jul 2022 20:14:29 +0200
Subject: [PATCH 38/77] Update actions
---
.github/workflows/test-pypy.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/test-pypy.yml b/.github/workflows/test-pypy.yml
index e4a53bb2..4800662e 100644
--- a/.github/workflows/test-pypy.yml
+++ b/.github/workflows/test-pypy.yml
@@ -34,7 +34,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
- name: setup-python ${{ matrix.pypy }}
id: setup-python
From b318cecd93bd700ebeebeba61bcae2f0231111ce Mon Sep 17 00:00:00 2001
From: Sven Serlier <85389871+wrt54g@users.noreply.github.com>
Date: Sun, 3 Jul 2022 20:15:21 +0200
Subject: [PATCH 39/77] Update actions/checkout to v3
---
.github/workflows/workflow.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml
index 171e2055..5c8cc77f 100644
--- a/.github/workflows/workflow.yml
+++ b/.github/workflows/workflow.yml
@@ -17,7 +17,7 @@ jobs:
operating-system: [ubuntu-latest, windows-latest]
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
- name: Set Node.js 16.x
uses: actions/setup-node@v3
From af97157ae6983e01c4eabbfb118b3e2ac549a4c0 Mon Sep 17 00:00:00 2001
From: Aarni Koskela
Date: Mon, 4 Jul 2022 12:24:58 +0300
Subject: [PATCH 40/77] doc: Add multiple wildcards example to readme
Based on https://www.npmjs.com/package/@actions/glob (the library used for cache file globbing), newline-separating multiple patterns is accepted.
---
README.md | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/README.md b/README.md
index 74e77aec..94500203 100644
--- a/README.md
+++ b/README.md
@@ -320,6 +320,21 @@ steps:
- run: pipenv install
```
+**Using a list of wildcard patterns to cache dependencies**
+```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-python@v4
+ with:
+ python-version: '3.10'
+ cache: 'pip'
+ cache-dependency-path: |
+ **/setup.cfg
+ **/requirements*.txt
+- run: pip install -e . -r subdirectory/requirements-dev.txt
+```
+
+
# Environment variables
The `update-environment` flag defaults to `true`.
From c4e89fac7e8767b327bbad6cb4d859eda999cf08 Mon Sep 17 00:00:00 2001
From: James
Date: Thu, 7 Jul 2022 22:34:44 +0100
Subject: [PATCH 41/77] Improve readme for 3.x and 3.11-dev style
python-version (#441)
---
README.md | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/README.md b/README.md
index 94500203..6e178e2f 100644
--- a/README.md
+++ b/README.md
@@ -127,6 +127,26 @@ steps:
- run: python my_script.py
```
+Download and set up the latest patch version of Python (for specified major & minor versions):
+```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-python@v4
+ with:
+ python-version: '3.11-dev'
+- run: python my_script.py
+```
+
+Download and set up the latest stable version of Python (for specified major version):
+```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
+- run: python my_script.py
+```
+
Download and set up PyPy:
```yaml
From 9a40041e255a2c42da53a3eb6e3b806ae7770e89 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Tue, 12 Jul 2022 16:38:54 +0200
Subject: [PATCH 42/77] Rearrange README.md, add advanced-usage.md
---
README.md | 428 +++++----------------------------------
docs/advanced-usage.md | 439 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 484 insertions(+), 383 deletions(-)
create mode 100644 docs/advanced-usage.md
diff --git a/README.md b/README.md
index 6e178e2f..a164bcc5 100644
--- a/README.md
+++ b/README.md
@@ -1,277 +1,60 @@
-# setup-python V4
+# setup-python
-This action sets up a Python environment for use in actions by:
+This action provides the following functionality for GitHub Actions users:
-- optionally installing and adding to PATH a version of Python that is already installed in the tools cache.
-- downloading, installing and adding to PATH an available version of Python from GitHub Releases ([actions/python-versions](https://github.com/actions/python-versions/releases)) if a specific version is not available in the tools cache.
-- failing if a specific version of Python is not preinstalled or available for download.
-- optionally caching dependencies for pip, pipenv and poetry.
-- registering problem matchers for error output.
+- Optionally downloading and installing the requested version of Python/PyPy and adding it to the PATH
+- Optionally caching dependencies for pip, pipenv and poetry
+- Registering problem matchers for error output
-# What's new
+## Table of contents
-- Ability to download, install and set up Python packages from `actions/python-versions` that do not come preinstalled on runners.
- - Allows for pinning to a specific patch version of Python without the worry of it ever being removed or changed.
-- Automatic setup and download of Python packages if using a self-hosted runner.
-- Support for pre-release versions of Python.
-- Support for installing any version of PyPy on-flight
-- Support for built-in caching of pip, pipenv and poetry dependencies
-- Support for `.python-version` file
+- [Basic usage](#basic-usage)
+- [Supported version syntax](#supported-version-syntax)
+- [Supported architectures](#supported-architectures)
+- [Caching packages dependencies](#caching-packages-dependencies)
+- [Advanced usage](#advanced-usage)
+- [License](#license)
+- [Contributions](#contributions)
-# Usage
+## Basic usage
See [action.yml](action.yml)
-Basic:
```yaml
steps:
- uses: actions/checkout@v3
-- uses: actions/setup-python@v4
+- uses: actions/setup-python@v4 # <- v4 is a major release tag of the action: https://github.com/actions/setup-python/tags
with:
- python-version: '3.x' # Version range or exact version of a Python version to use, using SemVer's version range syntax
- architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
+ python-version: '3.10'
- run: python my_script.py
```
+The `python-version` input is optional. If not supplied, the Python/PyPy version from the PATH will be used. The default version of Python/PyPy in PATH vary between runners and can be changed unexpectedly so we recommend always use `setup-python`.
-Read Python version from file:
-```yaml
-steps:
-- uses: actions/checkout@v3
-- uses: actions/setup-python@v4
- with:
- python-version-file: '.python-version' # Read python version from a file
-- run: python my_script.py
-```
+The action will first check the local [toolcache](docs/advanced-usage.md#hosted-tool-cache) for a [semver](https://github.com/npm/node-semver#versions) match. If unable to find a specific version in the tool cache, the action will attempt to download a version of Python from [GitHub Releases](https://github.com/actions/python-versions/releases) and for PyPy from the official [PyPy's dist](https://downloads.python.org/pypy/).
-Matrix Testing:
-```yaml
-jobs:
- build:
- runs-on: ubuntu-latest
- strategy:
- matrix:
- python-version: [ '2.x', '3.x', 'pypy2.7', 'pypy3.7', 'pypy3.8' ]
- name: Python ${{ matrix.python-version }} sample
- steps:
- - uses: actions/checkout@v3
- - name: Set up Python
- uses: actions/setup-python@v4
- with:
- python-version: ${{ matrix.python-version }}
- architecture: x64
- - run: python my_script.py
-```
+For information regarding locally cached versions of Python/PyPy on GitHub hosted runners, check out [GitHub Actions Virtual Environments](https://github.com/actions/virtual-environments).
-Exclude a specific Python version:
-```yaml
-jobs:
- build:
- runs-on: ${{ matrix.os }}
- strategy:
- matrix:
- os: [ubuntu-latest, macos-latest, windows-latest]
- python-version: ['2.7', '3.7', '3.8', '3.9', '3.10', 'pypy2.7', 'pypy3.8']
- exclude:
- - os: macos-latest
- python-version: '3.8'
- - os: windows-latest
- python-version: '3.6'
- steps:
- - uses: actions/checkout@v3
- - name: Set up Python
- uses: actions/setup-python@v4
- with:
- python-version: ${{ matrix.python-version }}
- - name: Display Python version
- run: python --version
-```
+## Supported version syntax
-Download and set up a version of Python that does not come preinstalled on an image:
-```yaml
-jobs:
- build:
- runs-on: ubuntu-latest
- strategy:
- matrix:
- # in this example, there is a newer version already installed, 3.7.7, so the older version will be downloaded
- python-version: ['3.7.4', '3.8', '3.9', '3.10']
- steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-python@v4
- with:
- python-version: ${{ matrix.python-version }}
- - run: python my_script.py
-```
+The `python-version` input supports the [Semantic Versioning Specification](https://github.com/npm/node-semver#versions) and some special version notations (e.g. `x.y-dev`), for detailed examples please refer to the section: [Using python-version input](docs/advanced-usage.md#using-python-version-input) of the [Advanced usage](docs/advanced-usage.md) guide.
-Download and set up an accurate pre-release version of Python:
-```yaml
-steps:
-- uses: actions/checkout@v3
-- uses: actions/setup-python@v4
- with:
- python-version: '3.11.0-alpha.1'
-- run: python my_script.py
-```
+## Supported architectures
-Download and set up the latest available version of Python (includes both pre-release and stable versions):
-```yaml
-steps:
-- uses: actions/checkout@v3
-- uses: actions/setup-python@v4
- with:
- python-version: '3.11.0-alpha - 3.11.0' # SemVer's version range syntax
-- run: python my_script.py
-```
+Using `architecture` input it's possible to specify required python's interpreter architecture: `x86` or `x64`. If input is not specified it defaults to `x64`.
-Download and set up the latest patch version of Python (for specified major & minor versions):
-```yaml
-steps:
-- uses: actions/checkout@v3
-- uses: actions/setup-python@v4
- with:
- python-version: '3.11-dev'
-- run: python my_script.py
-```
-
-Download and set up the latest stable version of Python (for specified major version):
-```yaml
-steps:
-- uses: actions/checkout@v3
-- uses: actions/setup-python@v4
- with:
- python-version: '3.x'
-- run: python my_script.py
-```
-
-Download and set up PyPy:
-
-```yaml
-jobs:
- build:
- runs-on: ubuntu-latest
- strategy:
- matrix:
- python-version:
- - 'pypy3.7' # the latest available version of PyPy that supports Python 3.7
- - 'pypy3.7-v7.3.3' # Python 3.7 and PyPy 7.3.3
- - 'pypy3.8' # the latest available version of PyPy that supports Python 3.8
- steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-python@v4
- with:
- python-version: ${{ matrix.python-version }}
- - run: python my_script.py
-```
-More details on PyPy syntax and examples of using preview / nightly versions of PyPy can be found in the [Available versions of PyPy](#available-versions-of-pypy) section.
-
-An output is available with the absolute path of the python interpreter executable if you need it:
-```yaml
-jobs:
- build:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-python@v4
- id: cp310
- with:
- python-version: "3.10"
- - run: pipx run --python '${{ steps.cp310.outputs.python-path }}' nox --version
-```
-
->The environment variable `pythonLocation` also becomes available after Python or PyPy installation. It contains the absolute path to the folder where the desired version of Python or PyPy is installed.
-
-# Getting started with Python + Actions
-
-Check out our detailed guide on using [Python with GitHub Actions](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/using-python-with-github-actions).
-
-# Available versions of Python
-
-`setup-python` is able to configure Python from two sources:
-
-- Preinstalled versions of Python in the tools cache on GitHub-hosted runners.
- - For detailed information regarding the available versions of Python that are installed, see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software).
- - For every minor version of Python, expect only the latest patch to be preinstalled.
- - If `3.8.1` is installed for example, and `3.8.2` is released, expect `3.8.1` to be removed and replaced by `3.8.2` in the tools cache.
- - If the exact patch version doesn't matter to you, specifying just the major and minor version will get you the latest preinstalled patch version. In the previous example, the version spec `3.8` will use the `3.8.2` Python version found in the cache.
- - Use `-dev` instead of a patch number (e.g., `3.11-dev`) to install the latest patch version release for a given minor version, *alpha and beta releases included*.
-- Downloadable Python versions from GitHub Releases ([actions/python-versions](https://github.com/actions/python-versions/releases)).
- - All available versions are listed in the [version-manifest.json](https://github.com/actions/python-versions/blob/main/versions-manifest.json) file.
- - If there is a specific version of Python that is not available, you can open an issue here
-
-**Note:** Python versions used in this action are generated in the [python-versions](https://github.com/actions/python-versions) repository. For macOS and Ubuntu images python versions are built from the source code. For Windows the python-versions repository uses installation executable. For more information please refer to the [python-versions](https://github.com/actions/python-versions) repository.
-
- # Available versions of PyPy
-
- `setup-python` is able to configure PyPy from two sources:
-
-- Preinstalled versions of PyPy in the tools cache on GitHub-hosted runners
- - For detailed information regarding the available versions of PyPy that are installed, see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software).
- - For the latest PyPy release, all versions of Python are cached.
- - Cache is updated with a 1-2 week delay. If you specify the PyPy version as `pypy3.7` or `pypy-3.7`, the cached version will be used although a newer version is available. If you need to start using the recently released version right after release, you should specify the exact PyPy version using `pypy3.7-v7.3.3` or `pypy-3.7-v7.3.3`.
-
-- Downloadable PyPy versions from the [official PyPy site](https://downloads.python.org/pypy/).
- - All available versions that we can download are listed in [versions.json](https://downloads.python.org/pypy/versions.json) file.
- - PyPy < 7.3.3 are not available to install on-flight.
- - If some versions are not available, you can open an issue in https://foss.heptapod.net/pypy/pypy/
-
-# Hosted Tool Cache
-
-GitHub hosted runners have a tools cache that comes with a few versions of Python + PyPy already installed. This tools cache helps speed up runs and tool setup by not requiring any new downloads. There is an environment variable called `RUNNER_TOOL_CACHE` on each runner that describes the location of this tools cache and there is where you will find Python and PyPy installed. `setup-python` works by taking a specific version of Python or PyPy in this tools cache and adding it to PATH.
-
-|| Location |
-|------|-------|
-|**Tool Cache Directory** |`RUNNER_TOOL_CACHE`|
-|**Python Tool Cache**|`RUNNER_TOOL_CACHE/Python/*`|
-|**PyPy Tool Cache**|`RUNNER_TOOL_CACHE/PyPy/*`|
-
-GitHub virtual environments are setup in [actions/virtual-environments](https://github.com/actions/virtual-environments). During the setup, the available versions of Python and PyPy are automatically downloaded, setup and documented.
-- Tools cache setup for Ubuntu: [Install-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/linux/scripts/installers/Install-Toolset.ps1) [Configure-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/linux/scripts/installers/Configure-Toolset.ps1)
-- Tools cache setup for Windows: [Install-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/win/scripts/Installers/Install-Toolset.ps1) [Configure-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/win/scripts/Installers/Configure-Toolset.ps1)
-
-# Specifying a Python version
-
-If there is a specific version of Python that you need and you don't want to worry about any potential breaking changes due to patch updates (going from `3.7.5` to `3.7.6` for example), you should specify the exact major, minor, and patch version (such as `3.7.5`)
- - The only downside to this is that set up will take a little longer since the exact version will have to be downloaded if the exact version is not already installed on the runner due to more recent versions.
- - MSI installers are used on Windows for this, so runs will take a little longer to set up vs Mac and Linux.
-
-You should specify only a major and minor version if you are okay with the most recent patch version being used.
- - There will be a single patch version already installed on each runner for every minor version of Python that is supported.
- - The patch version that will be preinstalled, will generally be the latest and every time there is a new patch released, the older version that is preinstalled will be replaced.
- - Using the most recent patch version will result in a very quick setup since no downloads will be required since a locally installed version Python on the runner will be used.
-
-# Specifying a PyPy version
-The version of PyPy should be specified in the format `pypy[-v]` or `pypy-[-v]`.
-The `` parameter is optional and can be skipped. The latest version will be used in this case.
-
-```
-pypy3.7 or pypy-3.7 # the latest available version of PyPy that supports Python 3.7
-pypy3.8 or pypy-3.8 # the latest available version of PyPy that supports Python 3.8
-pypy2.7 or pypy-2.7 # the latest available version of PyPy that supports Python 2.7
-pypy3.7-v7.3.3 or pypy-3.7-v7.3.3 # Python 3.7 and PyPy 7.3.3
-pypy3.7-v7.x or pypy-3.7-v7.x # Python 3.7 and the latest available PyPy 7.x
-pypy3.7-v7.3.3rc1 or pypy-3.7-v7.3.3rc1 # Python 3.7 and preview version of PyPy
-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.
-
-# Caching packages dependencies
+## 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.
-The action defaults to searching for a dependency file (`requirements.txt` for pip, `Pipfile.lock` for pipenv or `poetry.lock` for poetry) in the repository, and uses its hash as a part of the cache key. Use `cache-dependency-path` for cases where multiple dependency files are used, they are located in different subdirectories or different files for the hash want to be used.
+The action defaults to searching for a dependency file (`requirements.txt` for pip, `Pipfile.lock` for pipenv or `poetry.lock` for poetry) in the repository, and uses its hash as a part of the cache key. Input `cache-dependency-path` is used for cases when multiple dependency files are used, they are located in different subdirectories or different files for the hash want to be used.
- - For pip, the action will cache global cache directory
- - For pipenv, the action will cache virtualenv directory
- - For poetry, the action will cache virtualenv directory
-
-**Please Note:** Restored cache will not be used if the requirements.txt file is not updated for a long time and a newer version of the dependency is available that can lead to an increase in total build time.
-
-The requirements file format allows to specify dependency versions using logical operators (for example chardet>=3.0.4) or specify dependencies without any versions. In this case the pip install -r requirements.txt command will always try to install the latest available package version. To be sure that the cache will be used, please stick to a specific dependency version and update it manually if necessary.
+ - For `pip`, the action will cache global cache directory
+ - For `pipenv`, the action will cache virtualenv directory
+ - For `poetry`, the action will cache virtualenv directory
**Caching pip dependencies:**
@@ -281,152 +64,31 @@ steps:
- uses: actions/setup-python@v4
with:
python-version: '3.9'
- cache: 'pip'
+ cache: 'pip' # caching pip dependencies
- run: pip install -r requirements.txt
```
+>**Note:** Restored cache will not be used if the requirements.txt file is not updated for a long time and a newer version of the dependency is available that can lead to an increase in total build time.
-**Caching pipenv dependencies:**
-```yaml
-steps:
-- uses: actions/checkout@v3
-- uses: actions/setup-python@v4
- with:
- python-version: '3.9'
- cache: 'pipenv'
-- name: Install pipenv
- run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python
-- run: pipenv install
-```
+>The requirements file format allows to specify dependency versions using logical operators (for example chardet>=3.0.4) or specify dependencies without any versions. In this case the pip install -r requirements.txt command will always try to install the latest available package version. To be sure that the cache will be used, please stick to a specific dependency version and update it manually if necessary.
-**Caching poetry dependencies:**
-```yaml
-steps:
-- uses: actions/checkout@v3
-- name: Install poetry
- run: pipx install poetry
-- uses: actions/setup-python@v4
- with:
- python-version: '3.9'
- cache: 'poetry'
-- run: poetry install
-- run: poetry run pytest
-```
+See examples of using `cache` and `cache-dependency-path` for `pipenv` and `poetry` in the section: [Caching packages data](docs/advanced-usage.md#caching-packages-data) of the [Advanced usage](docs/advanced-usage.md) guide.
-**Using wildcard patterns to cache dependencies**
-```yaml
-steps:
-- uses: actions/checkout@v3
-- uses: actions/setup-python@v4
- with:
- python-version: '3.9'
- cache: 'pip'
- cache-dependency-path: '**/requirements-dev.txt'
-- run: pip install -r subdirectory/requirements-dev.txt
-```
+## Advanced usage
-**Using a list of file paths to cache dependencies**
-```yaml
-steps:
-- uses: actions/checkout@v3
-- uses: actions/setup-python@v4
- with:
- python-version: '3.9'
- cache: 'pipenv'
- cache-dependency-path: |
- server/app/Pipfile.lock
- __test__/app/Pipfile.lock
-- name: Install pipenv
- run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python
-- run: pipenv install
-```
+- [Using python-version input](docs/advanced-usage.md#using-python-version-input)
+- [Using python-version-file input](docs/advanced-usage.md#using-python-version-file-input)
+- [Check latest version](docs/advanced-usage.md#check-latest-version)
+- [Caching packages data](docs/advanced-usage.md#caching-packages-data)
+- [Environment variables and action's outputs](docs/advanced-usage.md#environment-variables-and-actions-outputs)
+- [Available versions of Python and PyPy](docs/advanced-usage.md#available-versions-of-python-and-pypy)
+- [Hosted Toolcache](docs/advanced-usage.md#hosted-tool-cache)
+- [Using `setup-python` with a self hosted runner](docs/advanced-usage.md#using-setup-python-with-a-self-hosted-runner)
+- [Using `setup-python` on GHES](docs/advanced-usage.md#using-setup-python-on-ghes)
-**Using a list of wildcard patterns to cache dependencies**
-```yaml
-steps:
-- uses: actions/checkout@v3
-- uses: actions/setup-python@v4
- with:
- python-version: '3.10'
- cache: 'pip'
- cache-dependency-path: |
- **/setup.cfg
- **/requirements*.txt
-- run: pip install -e . -r subdirectory/requirements-dev.txt
-```
-
-
-# Environment variables
-
- The `update-environment` flag defaults to `true`.
- With this setting, the action will add/update environment variables (e.g. `PATH`, `PKG_CONFIG_PATH`, `pythonLocation`) for `python` to just work out of the box.
-
- If `update-environment` is set to `false`, the action will not add/update environment variables.
- This can prove useful if you want the only side-effect to be to ensure python is installed and rely on the `python-path` output to run python.
- Such a requirement on side-effect could be because you don't want your composite action messing with your user's workflows.
-
- ```yaml
- steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-python@v4
- id: cp310
- with:
- python-version: '3.10'
- update-environment: false
- - run: ${{ steps.cp310.outputs.python-path }} my_script.py
- ```
-
-# Using `setup-python` with a self hosted runner
-
-Python distributions are only available for the same [environments](https://github.com/actions/virtual-environments#available-environments) that GitHub Actions hosted environments are available for. If you are using an unsupported version of Ubuntu such as `19.04` or another Linux distribution such as Fedora, `setup-python` will not work. If you have a supported self-hosted runner and you would like to use `setup-python`, there are a few extra things you need to make sure are set up so that new versions of Python can be downloaded and configured on your runner.
-
-If you are experiencing problems while configuring Python on your self-hosted runner, turn on [step debugging](https://github.com/actions/toolkit/blob/main/docs/action-debugging.md#step-debug-logs) to see addition logs.
-
-### Windows
-
-- Your runner needs to be running with administrator privileges so that the appropriate directories and files can be set up when downloading and installing a new version of Python for the first time.
-- If your runner is configured as a service, make sure the account that is running the service has the appropriate write permissions so that Python can get installed. The default `NT AUTHORITY\NETWORK SERVICE` should be sufficient.
-- You need `7zip` installed and added to your `PATH` so that the downloaded versions of Python files can be extracted properly during first-time setup.
-- MSI installers are used when setting up Python on Windows. A word of caution as MSI installers update registry settings.
-- The 3.8 MSI installer for Windows will not let you install another 3.8 version of Python. If `setup-python` fails for a 3.8 version of Python, make sure any previously installed versions are removed by going to "Apps & Features" in the Settings app.
-
-### Linux
-
-- The Python packages that are downloaded from `actions/python-versions` are originally compiled from source in `/opt/hostedtoolcache/` with the [--enable-shared](https://github.com/actions/python-versions/blob/94f04ae6806c6633c82db94c6406a16e17decd5c/builders/ubuntu-python-builder.psm1#L35) flag, which makes them non-relocatable.
-- By default runner downloads and install the tools to `/opt/hostedtoolcache`. The environment variable called `AGENT_TOOLSDIRECTORY` can be set to change this location.
- - In the same shell that your runner is using, type `export AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache`.
- - A more permanent way of setting the environment variable is to create a `.env` file in the same directory as your runner and to add `AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache`. This ensures the variable is always set if your runner is configured as a service.
-- Create a directory called `hostedtoolcache` inside `/opt`.
-- The user starting the runner must have write permission to the `/opt/hostedtoolcache` directory. It is not possible to start the Linux runner with `sudo` and the `/opt` directory usually requires root privileges to write to. Check the current user and group that the runner belongs to by typing `ls -l` inside the runners root directory.
-- The runner can be granted write access to the `/opt/hostedtoolcache` directory using a few techniques:
- - The user starting the runner is the owner, and the owner has write permission.
- - The user starting the runner is in the owning group, and the owning group has write permission.
- - All users have write permission.
-- One quick way to grant access is to change the user and group of `/opt/hostedtoolcache` to be the same as the runners using `chown`.
- - `sudo chown runner-user:runner-group /opt/hostedtoolcache/`.
-- If your runner is configured as a service and you run into problems, make sure the user that the service is running as is correct. For more information, you can [check the status of your self-hosted runner](https://help.github.com/en/actions/hosting-your-own-runners/configuring-the-self-hosted-runner-application-as-a-service#checking-the-status-of-the-service).
-
-### Mac
-
-- The same setup that applies to `Linux` also applies to `Mac`, just with a different tools cache directory.
-- Create a directory called `/Users/runner/hostedtoolcache`.
-- Set the `AGENT_TOOLSDIRECTORY` environment variable to `/Users/runner/hostedtoolcache`.
-- Change the permissions of `/Users/runner/hostedtoolcache` so that the runner has write access.
-
-
-# Using Python without `setup-python`
-
-`setup-python` helps keep your dependencies explicit and ensures consistent behavior between different runners. If you use `python` in a shell on a GitHub hosted runner without `setup-python` it will default to whatever is in PATH. The default version of Python in PATH vary between runners and can change unexpectedly so we recommend you always use `setup-python`.
-
-# Using `setup-python` on GHES
-
-`setup-python` comes pre-installed on the appliance with GHES if Actions is enabled. When dynamically downloading Python distributions, `setup-python` downloads distributions from [`actions/python-versions`](https://github.com/actions/python-versions) on github.com (outside of the appliance). These calls to `actions/python-versions` are made via unauthenticated requests, which are limited to [60 requests per hour per IP](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting). If more requests are made within the time frame, then you will start to see rate-limit errors during download that read `##[error]API rate limit exceeded for...`.
-
-To avoid hitting rate-limit problems, we recommend [setting up your own runner tool cache](https://docs.github.com/en/enterprise-server@2.22/admin/github-actions/managing-access-to-actions-from-githubcom/setting-up-the-tool-cache-on-self-hosted-runners-without-internet-access#about-the-included-setup-actions-and-the-runner-tool-cache).
-
-# License
+## License
The scripts and documentation in this project are released under the [MIT License](LICENSE).
-# Contributions
+## Contributions
-Contributions are welcome! See our [Contributor's Guide](docs/contributors.md).
+Contributions are welcome! See our [Contributor's Guide](docs/contributors.md).
\ No newline at end of file
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
new file mode 100644
index 00000000..874f5db0
--- /dev/null
+++ b/docs/advanced-usage.md
@@ -0,0 +1,439 @@
+# Table of contents
+- [Using python-version input](#using-python-version-file-input)
+ - [Specifying a Python version](#specifying-a-python-version)
+ - [Specifying a PyPy version](#specifying-a-pypy-version)
+ - [Matrix Testing](#matrix-testing)
+- [Using python-version-file input](#using-python-version-file-input)
+- [Check latest version](#check-latest-version)
+- [Caching packages data](#caching-packages-data)
+- [Environment variables and action's outputs](#environment-variables-and-actions-outputs)
+- [Available versions of Python and PyPy](#available-versions-of-python-and-pypy)
+ - [Python](#python)
+ - [PyPy](#pypy)
+- [Hosted Tool Cache](#hosted-tool-cache)
+- [Using `setup-python` with a self hosted runner](#using-setup-python-with-a-self-hosted-runner)
+ - [Windows](#windows)
+ - [Linux](#linux)
+ - [MacOS](#macos)
+- [Using `setup-python` on GHES](#using-setup-python-on-ghes)
+
+# Using python-version input
+
+The `python-version` input is used to specify the required version of Python or PyPy.
+
+## Specifying a Python version
+
+If there is a specific version of Python that you need and you don't want to worry about any potential breaking changes due to patch updates (going from `3.7.5` to `3.7.6` for example), you should specify the **exact major, minor, and patch version** (such as `3.7.5`):
+
+ ```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-python@v4
+ with:
+ python-version: '3.7.5'
+- run: python my_script.py
+```
+ - The only downside to this is that set up will take a little longer since the exact version will have to be downloaded if the exact version is not already installed on the runner due to more recent versions.
+ - MSI installers are used on Windows for this, so runs will take a little longer to set up vs MacOS and Linux.
+
+You should specify **only a major and minor version** if you are okay with the most recent patch version being used:
+
+ ```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-python@v4
+ with:
+ python-version: '3.7'
+- run: python my_script.py
+```
+ - There will be a single patch version already installed on each runner for every minor version of Python that is supported.
+ - The patch version that will be preinstalled, will generally be the latest and every time there is a new patch released, the older version that is preinstalled will be replaced.
+ - Using the most recent patch version will result in a very quick setup since no downloads will be required since a locally installed version Python on the runner will be used.
+
+You can specify version with **prerelease tag** to download and set up an accurate pre-release version of Python:
+
+```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-python@v4
+ with:
+ python-version: '3.11.0-alpha.1'
+- run: python my_script.py
+```
+
+It's also possible to use **x.y-dev syntax** to download and set up the latest patch version of Python, alpha and beta releases included. (for specified major & minor versions):
+
+```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-python@v4
+ with:
+ python-version: '3.11-dev'
+- run: python my_script.py
+```
+
+You can also use several types of ranges that are specified in [Semantic Versioning Specification](https://github.com/npm/node-semver#ranges), for instance:
+
+- **[hyphen ranges](https://github.com/npm/node-semver#hyphen-ranges-xyz---abc)** to download and set up the latest available version of Python (includes both pre-release and stable versions):
+
+```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-python@v4
+ with:
+ python-version: '3.11.0-alpha - 3.11.0'
+- run: python my_script.py
+```
+
+- **[x-ranges](https://github.com/npm/node-semver#x-ranges-12x-1x-12-)** to specify the latest stable version of Python (for specified major version):
+
+```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
+- run: python my_script.py
+```
+Please refer to the [Advanced range syntax section](https://github.com/npm/node-semver#advanced-range-syntax) of the [Semantic Versioning Specification](https://github.com/npm/node-semver) to check other available range syntaxes.
+
+## Specifying a PyPy version
+The version of PyPy should be specified in the format `pypy[-v]` or `pypy-[-v]`.
+The `-v` parameter is optional and can be skipped. The latest PyPy version will be used in this case.
+
+```
+pypy3.7 or pypy-3.7 # the latest available version of PyPy that supports Python 3.7
+pypy3.8 or pypy-3.8 # the latest available version of PyPy that supports Python 3.8
+pypy2.7 or pypy-2.7 # the latest available version of PyPy that supports Python 2.7
+pypy3.7-v7.3.3 or pypy-3.7-v7.3.3 # Python 3.7 and PyPy 7.3.3
+pypy3.7-v7.x or pypy-3.7-v7.x # Python 3.7 and the latest available PyPy 7.x
+pypy3.7-v7.3.3rc1 or pypy-3.7-v7.3.3rc1 # Python 3.7 and preview version of PyPy
+pypy3.7-nightly or pypy-3.7-nightly # Python 3.7 and nightly PyPy
+```
+
+Download and set up PyPy:
+
+```yaml
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ python-version:
+ - 'pypy3.7' # the latest available version of PyPy that supports Python 3.7
+ - 'pypy3.7-v7.3.3' # Python 3.7 and PyPy 7.3.3
+ - 'pypy3.8' # the latest available version of PyPy that supports Python 3.8
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.python-version }}
+ - run: python my_script.py
+```
+More details on PyPy syntax and examples of using preview / nightly versions of PyPy can be found in the [Available versions of PyPy](#pypy) section.
+
+## Matrix Testing
+
+Using `setup-python` it's possible to use [matrix syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix) to install several versions of Python/PyPy:
+
+```yaml
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ python-version: [ '2.x', '3.x', 'pypy2.7', 'pypy3.7', 'pypy3.8' ]
+ name: Python ${{ matrix.python-version }} sample
+ steps:
+ - uses: actions/checkout@v3
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.python-version }}
+ architecture: x64
+ - run: python my_script.py
+```
+
+Exclude a specific Python version:
+
+```yaml
+jobs:
+ build:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ubuntu-latest, macos-latest, windows-latest]
+ python-version: ['2.7', '3.7', '3.8', '3.9', '3.10', 'pypy2.7', 'pypy3.8']
+ exclude:
+ - os: macos-latest
+ python-version: '3.8'
+ - os: windows-latest
+ python-version: '3.6'
+ steps:
+ - uses: actions/checkout@v3
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Display Python version
+ run: python --version
+```
+
+# Using python-version-file input
+
+`setup-python` action has ability to read Python/PyPy version from a version file. `python-version-file` input is used for specifying path to the version file. If version file at the specified path doesn't exist action will try to find `.python-version` file implying that it as a default type of version files. If `.python-version` file doesn't exist also, action will fail with error.
+
+>In case both `python-version` and `python-version-file` inputs are supplied, `python-version-file` input will be ignored due to its lower priority.
+
+```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-python@v4
+ with:
+ python-version-file: '.python-version' # Read python version from a file .python-version
+- run: python my_script.py
+```
+# 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.
+
+```yaml
+steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-python@v3
+ with:
+ python-version: '3.7'
+ check-latest: true
+ - run: python my_script.py
+```
+> Setting `check-latest` to `true` has performance implications as downloading `Python/PyPy` versions is slower than using cached versions.
+
+
+# Caching packages data
+
+**Caching pipenv dependencies:**
+```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-python@v4
+ with:
+ python-version: '3.9'
+ cache: 'pipenv'
+- name: Install pipenv
+ run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python
+- run: pipenv install
+```
+
+**Caching poetry dependencies:**
+```yaml
+steps:
+- uses: actions/checkout@v3
+- name: Install poetry
+ run: pipx install poetry
+- uses: actions/setup-python@v4
+ with:
+ python-version: '3.9'
+ cache: 'poetry'
+- run: poetry install
+- run: poetry run pytest
+```
+**Using wildcard patterns to cache dependencies**
+```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-python@v4
+ with:
+ python-version: '3.9'
+ cache: 'pip'
+ cache-dependency-path: '**/requirements-dev.txt'
+- run: pip install -r subdirectory/requirements-dev.txt
+```
+
+**Using a list of file paths to cache dependencies**
+```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-python@v4
+ with:
+ python-version: '3.9'
+ cache: 'pipenv'
+ cache-dependency-path: |
+ server/app/Pipfile.lock
+ __test__/app/Pipfile.lock
+- name: Install pipenv
+ run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python
+- run: pipenv install
+```
+
+**Using a list of wildcard patterns to cache dependencies**
+```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-python@v4
+ with:
+ python-version: '3.10'
+ cache: 'pip'
+ cache-dependency-path: |
+ **/setup.cfg
+ **/requirements*.txt
+- run: pip install -e . -r subdirectory/requirements-dev.txt
+```
+
+# Environment variables and action's outputs
+
+## Action's outputs
+
+### `python-version`
+
+Using **python-version** output it's possible to get the installed by action python's version. This output is useful when the input `python-version` given as a range (e.g. 3.8.0 - 3.10.0 ), but down in a workflow you need to operate with exact installed version (e.g. 3.10.1).
+
+```yaml
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-python@v4
+ id: cp310
+ with:
+ python-version: "3.8.0 - 3.10.0"
+ - run: echo '${{ steps.cp310.outputs.python-version }}'
+```
+
+### `python-path`
+
+**python-path** output is available with the absolute path of the python interpreter executable if you need it:
+
+```yaml
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-python@v4
+ id: cp310
+ with:
+ python-version: "3.10"
+ - run: pipx run --python '${{ steps.cp310.outputs.python-path }}' nox --version
+```
+
+## Evironment variables
+
+These environment variables become available after setup-python action execution:
+
+| Env.Variable | Description |
+| ----------- | ----------- |
+| pythonLocation |Contains the absolute path to the folder where the requested version of Python or PyPy is installed|
+| Python_ROOT_DIR | https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython |
+| Python2_ROOT_DIR |https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython2|
+| Python3_ROOT_DIR |https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython3|
+
+## Using `update-environment` flag
+
+The `update-environment` flag defaults to `true`.
+With this setting, the action will add/update environment variables (e.g. `PATH`, `PKG_CONFIG_PATH`, `pythonLocation`) for `python` to just work out of the box.
+
+If `update-environment` is set to `false`, the action will not add/update environment variables.
+This can prove useful if you want the only side-effect to be to ensure python is installed and rely on the `python-path` output to run python.
+Such a requirement on side-effect could be because you don't want your composite action messing with your user's workflows.
+
+```yaml
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-python@v4
+ id: cp310
+ with:
+ python-version: '3.10'
+ update-environment: false
+ - run: ${{ steps.cp310.outputs.python-path }} my_script.py
+```
+# Available versions of Python and PyPy
+## Python
+
+`setup-python` is able to configure **Python** from two sources:
+
+- Preinstalled versions of Python in the toolcache on GitHub-hosted runners.
+ - For detailed information regarding the available versions of Python that are installed, see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software).
+ - For every minor version of Python, expect only the latest patch to be preinstalled.
+ - If `3.8.1` is installed for example, and `3.8.2` is released, expect `3.8.1` to be removed and replaced by `3.8.2` in the tools cache.
+ - If the exact patch version doesn't matter to you, specifying just the major and minor version will get you the latest preinstalled patch version. In the previous example, the version spec `3.8` will use the `3.8.2` Python version found in the cache.
+ - Use `-dev` instead of a patch number (e.g., `3.11-dev`) to install the latest patch version release for a given minor version, *alpha and beta releases included*.
+- Downloadable Python versions from GitHub Releases ([actions/python-versions](https://github.com/actions/python-versions/releases)).
+ - All available versions are listed in the [version-manifest.json](https://github.com/actions/python-versions/blob/main/versions-manifest.json) file.
+ - If there is a specific version of Python that is not available, you can open an issue here
+
+>**Note:** Python versions used in this action are generated in the [python-versions](https://github.com/actions/python-versions) repository. For macOS and Ubuntu images python versions are built from the source code. For Windows the python-versions repository uses installation executable. For more information please refer to the [python-versions](https://github.com/actions/python-versions) repository.
+
+## PyPy
+
+ `setup-python` is able to configure **PyPy** from two sources:
+
+- Preinstalled versions of PyPy in the tools cache on GitHub-hosted runners
+ - For detailed information regarding the available versions of PyPy that are installed, see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software).
+ - For the latest PyPy release, all versions of Python are cached.
+ - Cache is updated with a 1-2 week delay. If you specify the PyPy version as `pypy3.7` or `pypy-3.7`, the cached version will be used although a newer version is available. If you need to start using the recently released version right after release, you should specify the exact PyPy version using `pypy3.7-v7.3.3` or `pypy-3.7-v7.3.3`.
+
+- Downloadable PyPy versions from the [official PyPy site](https://downloads.python.org/pypy/).
+ - All available versions that we can download are listed in [versions.json](https://downloads.python.org/pypy/versions.json) file.
+ - PyPy < 7.3.3 are not available to install on-flight.
+ - If some versions are not available, you can open an issue in https://foss.heptapod.net/pypy/pypy/
+
+# Hosted Tool Cache
+
+GitHub hosted runners have a tool cache that comes with a few versions of Python + PyPy already installed. This tool cache helps speed up runs and tool setup by not requiring any new downloads. There is an environment variable called `RUNNER_TOOL_CACHE` on each runner that describes the location of this tools cache and there is where you will find Python and PyPy installed. `setup-python` works by taking a specific version of Python or PyPy in this tools cache and adding it to PATH.
+
+|| Location |
+|------|-------|
+|**Tool Cache Directory** |`RUNNER_TOOL_CACHE`|
+|**Python Tool Cache**|`RUNNER_TOOL_CACHE/Python/*`|
+|**PyPy Tool Cache**|`RUNNER_TOOL_CACHE/PyPy/*`|
+
+GitHub virtual environments are set up in [actions/virtual-environments](https://github.com/actions/virtual-environments). During the setup, the available versions of Python and PyPy are automatically downloaded, set up and documented.
+- Tool cache setup for Ubuntu: [Install-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/linux/scripts/installers/Install-Toolset.ps1) [Configure-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/linux/scripts/installers/Configure-Toolset.ps1)
+- Tool cache setup for Windows: [Install-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/win/scripts/Installers/Install-Toolset.ps1) [Configure-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/win/scripts/Installers/Configure-Toolset.ps1)
+
+
+# Using `setup-python` with a self hosted runner
+
+Python distributions are only available for the same [environments](https://github.com/actions/virtual-environments#available-environments) that GitHub Actions hosted environments are available for. If you are using an unsupported version of Ubuntu such as `19.04` or another Linux distribution such as Fedora, `setup-python` will not work. If you have a supported self-hosted runner and you would like to use `setup-python`, there are a few extra things you need to make sure are set up so that new versions of Python can be downloaded and configured on your runner.
+
+If you are experiencing problems while configuring Python on your self-hosted runner, turn on [step debugging](https://github.com/actions/toolkit/blob/main/docs/action-debugging.md#step-debug-logs) to see addition logs.
+
+### Windows
+
+- Your runner needs to be running with administrator privileges so that the appropriate directories and files can be set up when downloading and installing a new version of Python for the first time.
+- If your runner is configured as a service, make sure the account that is running the service has the appropriate write permissions so that Python can get installed. The default `NT AUTHORITY\NETWORK SERVICE` should be sufficient.
+- You need `7zip` installed and added to your `PATH` so that the downloaded versions of Python files can be extracted properly during first-time setup.
+- MSI installers are used when setting up Python on Windows. A word of caution as MSI installers update registry settings.
+- The 3.8 MSI installer for Windows will not let you install another 3.8 version of Python. If `setup-python` fails for a 3.8 version of Python, make sure any previously installed versions are removed by going to "Apps & Features" in the Settings app.
+
+### Linux
+
+- The Python packages that are downloaded from `actions/python-versions` are originally compiled from source in `/opt/hostedtoolcache/` with the [--enable-shared](https://github.com/actions/python-versions/blob/94f04ae6806c6633c82db94c6406a16e17decd5c/builders/ubuntu-python-builder.psm1#L35) flag, which makes them non-relocatable.
+- By default runner downloads and install the tools to `/opt/hostedtoolcache`. The environment variable called `AGENT_TOOLSDIRECTORY` can be set to change this location.
+ - In the same shell that your runner is using, type `export AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache`.
+ - A more permanent way of setting the environment variable is to create a `.env` file in the same directory as your runner and to add `AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache`. This ensures the variable is always set if your runner is configured as a service.
+- Create a directory called `hostedtoolcache` inside `/opt`.
+- The user starting the runner must have write permission to the `/opt/hostedtoolcache` directory. It is not possible to start the Linux runner with `sudo` and the `/opt` directory usually requires root privileges to write to. Check the current user and group that the runner belongs to by typing `ls -l` inside the runners root directory.
+- The runner can be granted write access to the `/opt/hostedtoolcache` directory using a few techniques:
+ - The user starting the runner is the owner, and the owner has write permission.
+ - The user starting the runner is in the owning group, and the owning group has write permission.
+ - All users have write permission.
+- One quick way to grant access is to change the user and group of `/opt/hostedtoolcache` to be the same as the runners using `chown`.
+ - `sudo chown runner-user:runner-group /opt/hostedtoolcache/`.
+- If your runner is configured as a service and you run into problems, make sure the user that the service is running as is correct. For more information, you can [check the status of your self-hosted runner](https://help.github.com/en/actions/hosting-your-own-runners/configuring-the-self-hosted-runner-application-as-a-service#checking-the-status-of-the-service).
+
+### MacOS
+
+- The same setup that applies to `Linux` also applies to `MacOS`, just with a different tools cache directory.
+- Create a directory called `/Users/runner/hostedtoolcache`.
+- Set the `AGENT_TOOLSDIRECTORY` environment variable to `/Users/runner/hostedtoolcache`.
+- Change the permissions of `/Users/runner/hostedtoolcache` so that the runner has write access.
+
+# Using `setup-python` on GHES
+
+`setup-python` comes pre-installed on the appliance with GHES if Actions is enabled. When dynamically downloading Python distributions, `setup-python` downloads distributions from [`actions/python-versions`](https://github.com/actions/python-versions) on github.com (outside of the appliance). These calls to `actions/python-versions` are made via unauthenticated requests, which are limited to [60 requests per hour per IP](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting). If more requests are made within the time frame, then you will start to see rate-limit errors during download that read `##[error]API rate limit exceeded for...`.
+
+To avoid hitting rate-limit problems, we recommend [setting up your own runner tool cache](https://docs.github.com/en/enterprise-server@2.22/admin/github-actions/managing-access-to-actions-from-githubcom/setting-up-the-tool-cache-on-self-hosted-runners-without-internet-access#about-the-included-setup-actions-and-the-runner-tool-cache).
From 6dd8ff72eb4e4246f636faddcd73bc7773ff8e42 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Tue, 12 Jul 2022 17:32:40 +0200
Subject: [PATCH 43/77] Change tool cache wording
---
README.md | 4 ++--
docs/advanced-usage.md | 18 +++++++++---------
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
index a164bcc5..4d8d55a6 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,7 @@ steps:
```
The `python-version` input is optional. If not supplied, the Python/PyPy version from the PATH will be used. The default version of Python/PyPy in PATH vary between runners and can be changed unexpectedly so we recommend always use `setup-python`.
-The action will first check the local [toolcache](docs/advanced-usage.md#hosted-tool-cache) for a [semver](https://github.com/npm/node-semver#versions) match. If unable to find a specific version in the tool cache, the action will attempt to download a version of Python from [GitHub Releases](https://github.com/actions/python-versions/releases) and for PyPy from the official [PyPy's dist](https://downloads.python.org/pypy/).
+The action will first check the local [tool cache](docs/advanced-usage.md#hosted-tool-cache) for a [semver](https://github.com/npm/node-semver#versions) match. If unable to find a specific version in the tool cache, the action will attempt to download a version of Python from [GitHub Releases](https://github.com/actions/python-versions/releases) and for PyPy from the official [PyPy's dist](https://downloads.python.org/pypy/).
For information regarding locally cached versions of Python/PyPy on GitHub hosted runners, check out [GitHub Actions Virtual Environments](https://github.com/actions/virtual-environments).
@@ -81,7 +81,7 @@ See examples of using `cache` and `cache-dependency-path` for `pipenv` and `poet
- [Caching packages data](docs/advanced-usage.md#caching-packages-data)
- [Environment variables and action's outputs](docs/advanced-usage.md#environment-variables-and-actions-outputs)
- [Available versions of Python and PyPy](docs/advanced-usage.md#available-versions-of-python-and-pypy)
-- [Hosted Toolcache](docs/advanced-usage.md#hosted-tool-cache)
+- [Hosted tool cache](docs/advanced-usage.md#hosted-tool-cache)
- [Using `setup-python` with a self hosted runner](docs/advanced-usage.md#using-setup-python-with-a-self-hosted-runner)
- [Using `setup-python` on GHES](docs/advanced-usage.md#using-setup-python-on-ghes)
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index 874f5db0..9c2d20c2 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -10,7 +10,7 @@
- [Available versions of Python and PyPy](#available-versions-of-python-and-pypy)
- [Python](#python)
- [PyPy](#pypy)
-- [Hosted Tool Cache](#hosted-tool-cache)
+- [Hosted tool cache](#hosted-tool-cache)
- [Using `setup-python` with a self hosted runner](#using-setup-python-with-a-self-hosted-runner)
- [Windows](#windows)
- [Linux](#linux)
@@ -354,10 +354,10 @@ Such a requirement on side-effect could be because you don't want your composite
`setup-python` is able to configure **Python** from two sources:
-- Preinstalled versions of Python in the toolcache on GitHub-hosted runners.
+- Preinstalled versions of Python in the tool cache on GitHub-hosted runners.
- For detailed information regarding the available versions of Python that are installed, see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software).
- For every minor version of Python, expect only the latest patch to be preinstalled.
- - If `3.8.1` is installed for example, and `3.8.2` is released, expect `3.8.1` to be removed and replaced by `3.8.2` in the tools cache.
+ - If `3.8.1` is installed for example, and `3.8.2` is released, expect `3.8.1` to be removed and replaced by `3.8.2` in the tool cache.
- If the exact patch version doesn't matter to you, specifying just the major and minor version will get you the latest preinstalled patch version. In the previous example, the version spec `3.8` will use the `3.8.2` Python version found in the cache.
- Use `-dev` instead of a patch number (e.g., `3.11-dev`) to install the latest patch version release for a given minor version, *alpha and beta releases included*.
- Downloadable Python versions from GitHub Releases ([actions/python-versions](https://github.com/actions/python-versions/releases)).
@@ -370,7 +370,7 @@ Such a requirement on side-effect could be because you don't want your composite
`setup-python` is able to configure **PyPy** from two sources:
-- Preinstalled versions of PyPy in the tools cache on GitHub-hosted runners
+- Preinstalled versions of PyPy in the tool cache on GitHub-hosted runners
- For detailed information regarding the available versions of PyPy that are installed, see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software).
- For the latest PyPy release, all versions of Python are cached.
- Cache is updated with a 1-2 week delay. If you specify the PyPy version as `pypy3.7` or `pypy-3.7`, the cached version will be used although a newer version is available. If you need to start using the recently released version right after release, you should specify the exact PyPy version using `pypy3.7-v7.3.3` or `pypy-3.7-v7.3.3`.
@@ -380,15 +380,15 @@ Such a requirement on side-effect could be because you don't want your composite
- PyPy < 7.3.3 are not available to install on-flight.
- If some versions are not available, you can open an issue in https://foss.heptapod.net/pypy/pypy/
-# Hosted Tool Cache
+# Hosted tool cache
-GitHub hosted runners have a tool cache that comes with a few versions of Python + PyPy already installed. This tool cache helps speed up runs and tool setup by not requiring any new downloads. There is an environment variable called `RUNNER_TOOL_CACHE` on each runner that describes the location of this tools cache and there is where you will find Python and PyPy installed. `setup-python` works by taking a specific version of Python or PyPy in this tools cache and adding it to PATH.
+GitHub hosted runners have a tool cache that comes with a few versions of Python + PyPy already installed. This tool cache helps speed up runs and tool setup by not requiring any new downloads. There is an environment variable called `RUNNER_TOOL_CACHE` on each runner that describes the location of this tool cache and there is where you will find Python and PyPy installed. `setup-python` works by taking a specific version of Python or PyPy in this tool cache and adding it to PATH.
|| Location |
|------|-------|
-|**Tool Cache Directory** |`RUNNER_TOOL_CACHE`|
-|**Python Tool Cache**|`RUNNER_TOOL_CACHE/Python/*`|
-|**PyPy Tool Cache**|`RUNNER_TOOL_CACHE/PyPy/*`|
+|**Tool cache Directory** |`RUNNER_TOOL_CACHE`|
+|**Python tool cache**|`RUNNER_TOOL_CACHE/Python/*`|
+|**PyPy tool cache**|`RUNNER_TOOL_CACHE/PyPy/*`|
GitHub virtual environments are set up in [actions/virtual-environments](https://github.com/actions/virtual-environments). During the setup, the available versions of Python and PyPy are automatically downloaded, set up and documented.
- Tool cache setup for Ubuntu: [Install-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/linux/scripts/installers/Install-Toolset.ps1) [Configure-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/linux/scripts/installers/Configure-Toolset.ps1)
From 746f28a2d3a31986ee65499d2e8b626b2e14fe29 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Wed, 13 Jul 2022 11:15:35 +0200
Subject: [PATCH 44/77] Update REAMDE.md and advanced-usage.md
---
README.md | 15 +++++++++--
docs/advanced-usage.md | 61 ++++++++++++++++++++++++++----------------
2 files changed, 51 insertions(+), 25 deletions(-)
diff --git a/README.md b/README.md
index 4d8d55a6..da0dd304 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,7 @@ This action provides the following functionality for GitHub Actions users:
See [action.yml](action.yml)
+**Python**
```yaml
steps:
- uses: actions/checkout@v3
@@ -32,6 +33,16 @@ steps:
python-version: '3.10'
- run: python my_script.py
```
+
+**PyPy**
+```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-python@v4
+ with:
+ python-version: 'pypy3.7'
+- run: python my_script.py
+```
The `python-version` input is optional. If not supplied, the Python/PyPy version from the PATH will be used. The default version of Python/PyPy in PATH vary between runners and can be changed unexpectedly so we recommend always use `setup-python`.
The action will first check the local [tool cache](docs/advanced-usage.md#hosted-tool-cache) for a [semver](https://github.com/npm/node-semver#versions) match. If unable to find a specific version in the tool cache, the action will attempt to download a version of Python from [GitHub Releases](https://github.com/actions/python-versions/releases) and for PyPy from the official [PyPy's dist](https://downloads.python.org/pypy/).
@@ -40,11 +51,11 @@ For information regarding locally cached versions of Python/PyPy on GitHub hoste
## Supported version syntax
-The `python-version` input supports the [Semantic Versioning Specification](https://github.com/npm/node-semver#versions) and some special version notations (e.g. `x.y-dev`), for detailed examples please refer to the section: [Using python-version input](docs/advanced-usage.md#using-python-version-input) of the [Advanced usage](docs/advanced-usage.md) guide.
+The `python-version` input supports the [Semantic Versioning Specification](https://semver.org/) and some special version notations (e.g. `semver ranges`, `x.y-dev syntax`, etc), for detailed examples please refer to the section: [Using python-version input](docs/advanced-usage.md#using-python-version-input) of the [Advanced usage](docs/advanced-usage.md) guide.
## Supported architectures
-Using `architecture` input it's possible to specify required python's interpreter architecture: `x86` or `x64`. If input is not specified it defaults to `x64`.
+Using `architecture` input it's possible to specify required python's interpreter architecture: `x86` or `x64`. If input is not specified the architecture defaults to `x64`.
## Caching packages dependencies
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index 9c2d20c2..a1944d47 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -36,7 +36,7 @@ steps:
- The only downside to this is that set up will take a little longer since the exact version will have to be downloaded if the exact version is not already installed on the runner due to more recent versions.
- MSI installers are used on Windows for this, so runs will take a little longer to set up vs MacOS and Linux.
-You should specify **only a major and minor version** if you are okay with the most recent patch version being used:
+You can specify **only a major and minor version** if you are okay with the most recent patch version being used:
```yaml
steps:
@@ -72,7 +72,7 @@ steps:
- run: python my_script.py
```
-You can also use several types of ranges that are specified in [Semantic Versioning Specification](https://github.com/npm/node-semver#ranges), for instance:
+You can also use several types of ranges that are specified in [semver](https://github.com/npm/node-semver#ranges), for instance:
- **[hyphen ranges](https://github.com/npm/node-semver#hyphen-ranges-xyz---abc)** to download and set up the latest available version of Python (includes both pre-release and stable versions):
@@ -95,14 +95,13 @@ steps:
python-version: '3.x'
- run: python my_script.py
```
-Please refer to the [Advanced range syntax section](https://github.com/npm/node-semver#advanced-range-syntax) of the [Semantic Versioning Specification](https://github.com/npm/node-semver) to check other available range syntaxes.
+Please refer to the [Advanced range syntax section](https://github.com/npm/node-semver#advanced-range-syntax) of the [semver](https://github.com/npm/node-semver) to check other available range syntaxes.
## Specifying a PyPy version
The version of PyPy should be specified in the format `pypy[-v]` or `pypy-[-v]`.
The `-v` parameter is optional and can be skipped. The latest PyPy version will be used in this case.
```
-pypy3.7 or pypy-3.7 # the latest available version of PyPy that supports Python 3.7
pypy3.8 or pypy-3.8 # the latest available version of PyPy that supports Python 3.8
pypy2.7 or pypy-2.7 # the latest available version of PyPy that supports Python 2.7
pypy3.7-v7.3.3 or pypy-3.7-v7.3.3 # Python 3.7 and PyPy 7.3.3
@@ -122,7 +121,6 @@ jobs:
python-version:
- 'pypy3.7' # the latest available version of PyPy that supports Python 3.7
- 'pypy3.7-v7.3.3' # Python 3.7 and PyPy 7.3.3
- - 'pypy3.8' # the latest available version of PyPy that supports Python 3.8
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
@@ -130,7 +128,7 @@ jobs:
python-version: ${{ matrix.python-version }}
- run: python my_script.py
```
-More details on PyPy syntax and examples of using preview / nightly versions of PyPy can be found in the [Available versions of PyPy](#pypy) section.
+More details on PyPy syntax can be found in the [Available versions of PyPy](#pypy) section.
## Matrix Testing
@@ -239,17 +237,6 @@ steps:
- run: poetry install
- run: poetry run pytest
```
-**Using wildcard patterns to cache dependencies**
-```yaml
-steps:
-- uses: actions/checkout@v3
-- uses: actions/setup-python@v4
- with:
- python-version: '3.9'
- cache: 'pip'
- cache-dependency-path: '**/requirements-dev.txt'
-- run: pip install -r subdirectory/requirements-dev.txt
-```
**Using a list of file paths to cache dependencies**
```yaml
@@ -266,6 +253,17 @@ steps:
run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python
- run: pipenv install
```
+**Using wildcard patterns to cache dependencies**
+```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-python@v4
+ with:
+ python-version: '3.9'
+ cache: 'pip'
+ cache-dependency-path: '**/requirements-dev.txt'
+- run: pip install -r subdirectory/requirements-dev.txt
+```
**Using a list of wildcard patterns to cache dependencies**
```yaml
@@ -287,7 +285,7 @@ steps:
### `python-version`
-Using **python-version** output it's possible to get the installed by action python's version. This output is useful when the input `python-version` given as a range (e.g. 3.8.0 - 3.10.0 ), but down in a workflow you need to operate with exact installed version (e.g. 3.10.1).
+Using **python-version** output it's possible to get the installed by action Pytho/PyPy version. This output is useful when the input `python-version` given as a range (e.g. 3.8.0 - 3.10.0 ), but down in a workflow you need to operate with the exact installed version (e.g. 3.10.1).
```yaml
jobs:
@@ -304,7 +302,7 @@ jobs:
### `python-path`
-**python-path** output is available with the absolute path of the python interpreter executable if you need it:
+**python-path** output is available with the absolute path of the Python/PyPy interpreter executable if you need it:
```yaml
jobs:
@@ -318,12 +316,29 @@ jobs:
python-version: "3.10"
- run: pipx run --python '${{ steps.cp310.outputs.python-path }}' nox --version
```
+### `cache-hit`
+
+**cache-hit** output is available with a boolean value that indicates whether a cache hit occured on the primary key:
+
+```
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-python@v4
+ id: cp310
+ with:
+ python-version: "3.8.0"
+ cache: "poetry"
+ - run: echo '${{ steps.cp310.outputs.cache-hit }}' # true if cache-hit occured on the primary key
+```
## Evironment variables
These environment variables become available after setup-python action execution:
-| Env.Variable | Description |
+| **Env.variable** | **Description** |
| ----------- | ----------- |
| pythonLocation |Contains the absolute path to the folder where the requested version of Python or PyPy is installed|
| Python_ROOT_DIR | https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython |
@@ -333,10 +348,10 @@ These environment variables become available after setup-python action execution
## Using `update-environment` flag
The `update-environment` flag defaults to `true`.
-With this setting, the action will add/update environment variables (e.g. `PATH`, `PKG_CONFIG_PATH`, `pythonLocation`) for `python` to just work out of the box.
+With this setting, the action will add/update environment variables (e.g. `PATH`, `PKG_CONFIG_PATH`, `pythonLocation`) for Python/PyPy to just work out of the box.
If `update-environment` is set to `false`, the action will not add/update environment variables.
-This can prove useful if you want the only side-effect to be to ensure python is installed and rely on the `python-path` output to run python.
+This can prove useful if you want the only side-effect to be to ensure Python/PyPy is installed and rely on the `python-path` output to run executable.
Such a requirement on side-effect could be because you don't want your composite action messing with your user's workflows.
```yaml
@@ -382,7 +397,7 @@ Such a requirement on side-effect could be because you don't want your composite
# Hosted tool cache
-GitHub hosted runners have a tool cache that comes with a few versions of Python + PyPy already installed. This tool cache helps speed up runs and tool setup by not requiring any new downloads. There is an environment variable called `RUNNER_TOOL_CACHE` on each runner that describes the location of this tool cache and there is where you will find Python and PyPy installed. `setup-python` works by taking a specific version of Python or PyPy in this tool cache and adding it to PATH.
+GitHub hosted runners have a tool cache that comes with a few versions of Python + PyPy already installed. This tool cache helps speed up runs and tool setup by not requiring any new downloads. There is an environment variable called `RUNNER_TOOL_CACHE` on each runner that describes the location of the tool cache with Python and PyPy installed. `setup-python` works by taking a specific version of Python or PyPy from this tool cache and adding it to PATH.
|| Location |
|------|-------|
From 09086ccd4627c1947935882314572a89b021ab31 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Wed, 13 Jul 2022 11:27:41 +0200
Subject: [PATCH 45/77] Update action.yml file
---
action.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/action.yml b/action.yml
index de2a4feb..9810aeb7 100644
--- a/action.yml
+++ b/action.yml
@@ -4,7 +4,7 @@ description: 'Set up a specific version of Python and add the command-line tools
author: 'GitHub'
inputs:
python-version:
- description: "Version range or exact version of Python to use, using SemVer's version range syntax. Reads from .python-version if unset."
+ description: "Version range or exact version of Python to use, using SemVer's version range syntax."
python-version-file:
description: "File containing the Python version to use. Example: .python-version"
cache:
@@ -22,7 +22,7 @@ inputs:
default: true
outputs:
python-version:
- description: "The installed python version. Useful when given a version range as input."
+ description: "The installed Python version. Useful when given a version range as input."
cache-hit:
description: 'A boolean value to indicate a cache entry was found'
python-path:
From 61fb4e42abc1a8d063ecad4c918c01937dd9aa7c Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Wed, 13 Jul 2022 12:17:04 +0200
Subject: [PATCH 46/77] Fix review points
---
README.md | 14 ++------------
action.yml | 12 ++++++------
docs/advanced-usage.md | 2 +-
3 files changed, 9 insertions(+), 19 deletions(-)
diff --git a/README.md b/README.md
index da0dd304..44da1fb2 100644
--- a/README.md
+++ b/README.md
@@ -10,16 +10,6 @@ This action provides the following functionality for GitHub Actions users:
- Optionally caching dependencies for pip, pipenv and poetry
- Registering problem matchers for error output
-## Table of contents
-
-- [Basic usage](#basic-usage)
-- [Supported version syntax](#supported-version-syntax)
-- [Supported architectures](#supported-architectures)
-- [Caching packages dependencies](#caching-packages-dependencies)
-- [Advanced usage](#advanced-usage)
-- [License](#license)
-- [Contributions](#contributions)
-
## Basic usage
See [action.yml](action.yml)
@@ -40,7 +30,7 @@ steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
- python-version: 'pypy3.7'
+ python-version: 'pypy3.9'
- run: python my_script.py
```
The `python-version` input is optional. If not supplied, the Python/PyPy version from the PATH will be used. The default version of Python/PyPy in PATH vary between runners and can be changed unexpectedly so we recommend always use `setup-python`.
@@ -51,7 +41,7 @@ For information regarding locally cached versions of Python/PyPy on GitHub hoste
## Supported version syntax
-The `python-version` input supports the [Semantic Versioning Specification](https://semver.org/) and some special version notations (e.g. `semver ranges`, `x.y-dev syntax`, etc), for detailed examples please refer to the section: [Using python-version input](docs/advanced-usage.md#using-python-version-input) of the [Advanced usage](docs/advanced-usage.md) guide.
+The `python-version` input supports the [Semantic Versioning Specification](https://semver.org/) and some special version notations (e.g. `semver ranges`, `x.y-dev syntax`, etc.), for detailed examples please refer to the section: [Using python-version input](docs/advanced-usage.md#using-python-version-input) of the [Advanced usage](docs/advanced-usage.md) guide.
## Supported architectures
diff --git a/action.yml b/action.yml
index 9810aeb7..e0f2ba1b 100644
--- a/action.yml
+++ b/action.yml
@@ -4,16 +4,16 @@ description: 'Set up a specific version of Python and add the command-line tools
author: 'GitHub'
inputs:
python-version:
- description: "Version range or exact version of Python to use, using SemVer's version range syntax."
+ description: 'Version range or exact version of Python/PyPy to use, using SemVer's version range syntax.'
python-version-file:
- description: "File containing the Python version to use. Example: .python-version"
+ description: 'File containing the Python version to use. Example: .python-version'
cache:
description: 'Used to specify a package manager for caching in the default directory. Supported values: pip, pipenv, poetry.'
required: false
architecture:
- description: 'The target architecture (x86, x64) of the Python interpreter.'
+ description: 'The target architecture (x86, x64) of the Python/PyPy interpreter.'
token:
- description: Used to pull python distributions from actions/python-versions. Since there's a default, this is typically not supplied by the user.
+ description: 'Used to pull python distributions from actions/python-versions. Since there's a default, this is typically not supplied by the user.'
default: ${{ github.token }}
cache-dependency-path:
description: 'Used to specify the path to dependency files. Supports wildcards or a list of file names for caching multiple dependencies.'
@@ -22,11 +22,11 @@ inputs:
default: true
outputs:
python-version:
- description: "The installed Python version. Useful when given a version range as input."
+ description: 'The installed Python/PyPy version. Useful when given a version range as input.'
cache-hit:
description: 'A boolean value to indicate a cache entry was found'
python-path:
- description: "The absolute path to the Python executable."
+ description: 'The absolute path to the Python/PyPy executable.'
runs:
using: 'node16'
main: 'dist/setup/index.js'
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index a1944d47..69a303ce 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -285,7 +285,7 @@ steps:
### `python-version`
-Using **python-version** output it's possible to get the installed by action Pytho/PyPy version. This output is useful when the input `python-version` given as a range (e.g. 3.8.0 - 3.10.0 ), but down in a workflow you need to operate with the exact installed version (e.g. 3.10.1).
+Using **python-version** output it's possible to get the installed by action Python/PyPy version. This output is useful when the input `python-version` given as a range (e.g. 3.8.0 - 3.10.0 ), but down in a workflow you need to operate with the exact installed version (e.g. 3.10.1).
```yaml
jobs:
From 386e4eaaedc52f72c24a57219575a72956958c4c Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Wed, 13 Jul 2022 13:34:22 +0200
Subject: [PATCH 47/77] Fix review points
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 44da1fb2..8710b8f6 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
-This action provides the following functionality for GitHub Actions users:
+This action provides the following functionalities for GitHub Actions users:
- Optionally downloading and installing the requested version of Python/PyPy and adding it to the PATH
- Optionally caching dependencies for pip, pipenv and poetry
@@ -45,7 +45,7 @@ The `python-version` input supports the [Semantic Versioning Specification](http
## Supported architectures
-Using `architecture` input it's possible to specify required python's interpreter architecture: `x86` or `x64`. If input is not specified the architecture defaults to `x64`.
+Using `architecture` input it is possible to specify required Python/PyPy interpreter architecture: `x86` or `x64`. If input is not specified the architecture defaults to `x64`.
## Caching packages dependencies
From 799afeb7961a4c779201d81d65b3b751b191a021 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Wed, 13 Jul 2022 13:43:28 +0200
Subject: [PATCH 48/77] Fix action.yml file
---
action.yml | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/action.yml b/action.yml
index e0f2ba1b..f767b428 100644
--- a/action.yml
+++ b/action.yml
@@ -4,16 +4,19 @@ description: 'Set up a specific version of Python and add the command-line tools
author: 'GitHub'
inputs:
python-version:
- description: 'Version range or exact version of Python/PyPy to use, using SemVer's version range syntax.'
+ description: "Version range or exact version of Python/PyPy to use, using SemVer's version range syntax."
python-version-file:
- description: 'File containing the Python version to use. Example: .python-version'
+ description: "File containing the Python version to use. Example: .python-version"
cache:
description: 'Used to specify a package manager for caching in the default directory. Supported values: pip, pipenv, poetry.'
required: false
architecture:
- description: 'The target architecture (x86, x64) of the Python/PyPy interpreter.'
+ description: "The target architecture (x86, x64) of the Python/PyPy 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.'
+ 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 }}
cache-dependency-path:
description: 'Used to specify the path to dependency files. Supports wildcards or a list of file names for caching multiple dependencies.'
@@ -22,11 +25,11 @@ inputs:
default: true
outputs:
python-version:
- description: 'The installed Python/PyPy version. Useful when given a version range as input.'
+ description: "The installed Python/PyPy version. Useful when given a version range as input."
cache-hit:
description: 'A boolean value to indicate a cache entry was found'
python-path:
- description: 'The absolute path to the Python/PyPy executable.'
+ description: "The absolute path to the Python/PyPy executable."
runs:
using: 'node16'
main: 'dist/setup/index.js'
From b88a682917db311eac9aab40569d7ee9db572924 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Fri, 15 Jul 2022 16:52:20 +0200
Subject: [PATCH 49/77] Fix resolveVersionInput() logic
---
dist/setup/index.js | 15 +++++++++------
src/setup-python.ts | 22 ++++++++++++----------
2 files changed, 21 insertions(+), 16 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 9ac89a4f..57bd35fe 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -65262,17 +65262,20 @@ function resolveVersionInput() {
}
if (versionFile) {
if (!fs_1.default.existsSync(versionFile)) {
- logWarning(`The specified python version file at: ${versionFile} doesn't exist. Attempting to find .python-version file.`);
- versionFile = '.python-version';
- if (!fs_1.default.existsSync(versionFile)) {
- throw new Error(`The ${versionFile} doesn't exist.`);
- }
+ throw new Error(`The specified python version file at: ${versionFile} doesn't exist.`);
}
version = fs_1.default.readFileSync(versionFile, 'utf8');
core.info(`Resolved ${versionFile} as ${version}`);
return version;
}
- core.warning("Neither 'python-version' nor 'python-version-file' inputs were supplied.");
+ logWarning("Neither 'python-version' nor 'python-version-file' inputs were supplied. Attempting to find '.python-version' file.");
+ versionFile = '.python-version';
+ if (fs_1.default.existsSync(versionFile)) {
+ version = fs_1.default.readFileSync(versionFile, 'utf8');
+ core.info(`Resolved ${versionFile} as ${version}`);
+ return version;
+ }
+ logWarning(`${versionFile} doesn't exist.`);
return version;
}
function run() {
diff --git a/src/setup-python.ts b/src/setup-python.ts
index db17735b..23356889 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -38,24 +38,26 @@ function resolveVersionInput(): string {
if (versionFile) {
if (!fs.existsSync(versionFile)) {
- logWarning(
- `The specified python version file at: ${versionFile} doesn't exist. Attempting to find .python-version file.`
+ throw new Error(
+ `The specified python version file at: ${versionFile} doesn't exist.`
);
- versionFile = '.python-version';
- if (!fs.existsSync(versionFile)) {
- throw new Error(`The ${versionFile} doesn't exist.`);
- }
}
-
version = fs.readFileSync(versionFile, 'utf8');
core.info(`Resolved ${versionFile} as ${version}`);
-
return version;
}
- core.warning(
- "Neither 'python-version' nor 'python-version-file' inputs were supplied."
+ logWarning(
+ "Neither 'python-version' nor 'python-version-file' inputs were supplied. Attempting to find '.python-version' file."
);
+ versionFile = '.python-version';
+ if (fs.existsSync(versionFile)) {
+ version = fs.readFileSync(versionFile, 'utf8');
+ core.info(`Resolved ${versionFile} as ${version}`);
+ return version;
+ }
+
+ logWarning(`${versionFile} doesn't exist.`);
return version;
}
From 5517d5f7b547a5c566879ca95b0f57267f3641a3 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Mon, 18 Jul 2022 14:33:42 +0200
Subject: [PATCH 50/77] Fix documentation
Docs were updated to incorporate changes regarding tool cache folder
on the self-hosted runner and changes in resolveVersionInput()
---
README.md | 2 +-
docs/advanced-usage.md | 29 +++--------------------------
2 files changed, 4 insertions(+), 27 deletions(-)
diff --git a/README.md b/README.md
index 8710b8f6..56cfaa0c 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@ steps:
python-version: 'pypy3.9'
- run: python my_script.py
```
-The `python-version` input is optional. If not supplied, the Python/PyPy version from the PATH will be used. The default version of Python/PyPy in PATH vary between runners and can be changed unexpectedly so we recommend always use `setup-python`.
+The `python-version` input is optional. If not supplied, the action will try to resolve version from the default `.python-version` file. If `.python-version` file doesn't exist Python/PyPy version from the PATH will be used. The default version of Python/PyPy in PATH vary between runners and can be changed unexpectedly so we recommend always use `setup-python`.
The action will first check the local [tool cache](docs/advanced-usage.md#hosted-tool-cache) for a [semver](https://github.com/npm/node-semver#versions) match. If unable to find a specific version in the tool cache, the action will attempt to download a version of Python from [GitHub Releases](https://github.com/actions/python-versions/releases) and for PyPy from the official [PyPy's dist](https://downloads.python.org/pypy/).
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index 69a303ce..407d0254 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -179,7 +179,7 @@ jobs:
# Using python-version-file input
-`setup-python` action has ability to read Python/PyPy version from a version file. `python-version-file` input is used for specifying path to the version file. If version file at the specified path doesn't exist action will try to find `.python-version` file implying that it as a default type of version files. If `.python-version` file doesn't exist also, action will fail with error.
+`setup-python` action has ability to read Python/PyPy version from a version file. `python-version-file` input is used for specifying path to the version file. If `.python-version` file doesn't exist, action will fail with error.
>In case both `python-version` and `python-version-file` inputs are supplied, `python-version-file` input will be ignored due to its lower priority.
@@ -414,9 +414,7 @@ GitHub virtual environments are set up in [actions/virtual-environments](https:/
Python distributions are only available for the same [environments](https://github.com/actions/virtual-environments#available-environments) that GitHub Actions hosted environments are available for. If you are using an unsupported version of Ubuntu such as `19.04` or another Linux distribution such as Fedora, `setup-python` will not work. If you have a supported self-hosted runner and you would like to use `setup-python`, there are a few extra things you need to make sure are set up so that new versions of Python can be downloaded and configured on your runner.
-If you are experiencing problems while configuring Python on your self-hosted runner, turn on [step debugging](https://github.com/actions/toolkit/blob/main/docs/action-debugging.md#step-debug-logs) to see addition logs.
-
-### Windows
+## Windows requirements
- Your runner needs to be running with administrator privileges so that the appropriate directories and files can be set up when downloading and installing a new version of Python for the first time.
- If your runner is configured as a service, make sure the account that is running the service has the appropriate write permissions so that Python can get installed. The default `NT AUTHORITY\NETWORK SERVICE` should be sufficient.
@@ -424,28 +422,7 @@ If you are experiencing problems while configuring Python on your self-hosted ru
- MSI installers are used when setting up Python on Windows. A word of caution as MSI installers update registry settings.
- The 3.8 MSI installer for Windows will not let you install another 3.8 version of Python. If `setup-python` fails for a 3.8 version of Python, make sure any previously installed versions are removed by going to "Apps & Features" in the Settings app.
-### Linux
-
-- The Python packages that are downloaded from `actions/python-versions` are originally compiled from source in `/opt/hostedtoolcache/` with the [--enable-shared](https://github.com/actions/python-versions/blob/94f04ae6806c6633c82db94c6406a16e17decd5c/builders/ubuntu-python-builder.psm1#L35) flag, which makes them non-relocatable.
-- By default runner downloads and install the tools to `/opt/hostedtoolcache`. The environment variable called `AGENT_TOOLSDIRECTORY` can be set to change this location.
- - In the same shell that your runner is using, type `export AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache`.
- - A more permanent way of setting the environment variable is to create a `.env` file in the same directory as your runner and to add `AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache`. This ensures the variable is always set if your runner is configured as a service.
-- Create a directory called `hostedtoolcache` inside `/opt`.
-- The user starting the runner must have write permission to the `/opt/hostedtoolcache` directory. It is not possible to start the Linux runner with `sudo` and the `/opt` directory usually requires root privileges to write to. Check the current user and group that the runner belongs to by typing `ls -l` inside the runners root directory.
-- The runner can be granted write access to the `/opt/hostedtoolcache` directory using a few techniques:
- - The user starting the runner is the owner, and the owner has write permission.
- - The user starting the runner is in the owning group, and the owning group has write permission.
- - All users have write permission.
-- One quick way to grant access is to change the user and group of `/opt/hostedtoolcache` to be the same as the runners using `chown`.
- - `sudo chown runner-user:runner-group /opt/hostedtoolcache/`.
-- If your runner is configured as a service and you run into problems, make sure the user that the service is running as is correct. For more information, you can [check the status of your self-hosted runner](https://help.github.com/en/actions/hosting-your-own-runners/configuring-the-self-hosted-runner-application-as-a-service#checking-the-status-of-the-service).
-
-### MacOS
-
-- The same setup that applies to `Linux` also applies to `MacOS`, just with a different tools cache directory.
-- Create a directory called `/Users/runner/hostedtoolcache`.
-- Set the `AGENT_TOOLSDIRECTORY` environment variable to `/Users/runner/hostedtoolcache`.
-- Change the permissions of `/Users/runner/hostedtoolcache` so that the runner has write access.
+>If you are experiencing problems while configuring Python on your self-hosted runner, turn on [step debugging](https://github.com/actions/toolkit/blob/main/docs/action-debugging.md#step-debug-logs) to see addition logs.
# Using `setup-python` on GHES
From 592a7a7a45a48972db5452787b01b1f407e38948 Mon Sep 17 00:00:00 2001
From: Milos Pantic <101411245+panticmilos@users.noreply.github.com>
Date: Tue, 19 Jul 2022 14:20:19 +0200
Subject: [PATCH 51/77] Add linux os release info to primary key (#467)
---
__tests__/cache-restore.test.ts | 23 +++++++++++++++---
dist/setup/index.js | 36 +++++++++++++++++++++++++---
src/cache-distributions/pip-cache.ts | 15 +++++++++---
src/utils.ts | 17 +++++++++++++
4 files changed, 82 insertions(+), 9 deletions(-)
diff --git a/__tests__/cache-restore.test.ts b/__tests__/cache-restore.test.ts
index 573f36a9..b0d44b8f 100644
--- a/__tests__/cache-restore.test.ts
+++ b/__tests__/cache-restore.test.ts
@@ -2,6 +2,7 @@ import * as core from '@actions/core';
import * as cache from '@actions/cache';
import * as exec from '@actions/exec';
import {getCacheDistributor} from '../src/cache-distributions/cache-factory';
+import * as utils from './../src/utils';
describe('restore-cache', () => {
const pipFileLockHash =
@@ -28,6 +29,7 @@ virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/py
let saveSatetSpy: jest.SpyInstance;
let getStateSpy: jest.SpyInstance;
let setOutputSpy: jest.SpyInstance;
+ let getLinuxOSReleaseInfoSpy: jest.SpyInstance;
// cache spy
let restoreCacheSpy: jest.SpyInstance;
@@ -74,6 +76,8 @@ virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/py
return primaryKey;
}
);
+
+ getLinuxOSReleaseInfoSpy = jest.spyOn(utils, 'getLinuxOSReleaseInfo');
});
describe('Validate provided package manager', () => {
@@ -109,11 +113,24 @@ virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/py
pythonVersion,
dependencyFile
);
+
+ if (process.platform === 'linux') {
+ getLinuxOSReleaseInfoSpy.mockImplementation(() =>
+ Promise.resolve('Ubuntu-20.4')
+ );
+ }
+
await cacheDistributor.restoreCache();
- expect(infoSpy).toHaveBeenCalledWith(
- `Cache restored from key: setup-python-${process.env['RUNNER_OS']}-python-${pythonVersion}-${packageManager}-${fileHash}`
- );
+ if (process.platform === 'linux' && packageManager === 'pip') {
+ expect(infoSpy).toHaveBeenCalledWith(
+ `Cache restored from key: setup-python-${process.env['RUNNER_OS']}-Ubuntu-20.4-python-${pythonVersion}-${packageManager}-${fileHash}`
+ );
+ } else {
+ expect(infoSpy).toHaveBeenCalledWith(
+ `Cache restored from key: setup-python-${process.env['RUNNER_OS']}-python-${pythonVersion}-${packageManager}-${fileHash}`
+ );
+ }
},
30000
);
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 57bd35fe..dec74449 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -64430,8 +64430,17 @@ class PipCache extends cache_distributor_1.default {
computeKeys() {
return __awaiter(this, void 0, void 0, function* () {
const hash = yield glob.hashFiles(this.cacheDependencyPath);
- const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}-${hash}`;
- const restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}`;
+ let primaryKey = '';
+ let restoreKey = '';
+ if (utils_1.IS_LINUX) {
+ const osRelease = yield utils_1.getLinuxOSReleaseInfo();
+ primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${osRelease}-python-${this.pythonVersion}-${this.packageManager}-${hash}`;
+ restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${osRelease}-python-${this.pythonVersion}-${this.packageManager}`;
+ }
+ else {
+ primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}-${hash}`;
+ restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}`;
+ }
return {
primaryKey,
restoreKey: [restoreKey]
@@ -65357,16 +65366,26 @@ var __importStar = (this && this.__importStar) || function (mod) {
__setModuleDefault(result, mod);
return result;
};
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.isCacheFeatureAvailable = exports.isGhes = exports.validatePythonVersionFormatForPyPy = exports.writeExactPyPyVersionFile = exports.readExactPyPyVersionFile = exports.getPyPyVersionFromPath = exports.isNightlyKeyword = exports.validateVersion = exports.createSymlinkInFolder = exports.WINDOWS_PLATFORMS = exports.WINDOWS_ARCHS = exports.IS_LINUX = exports.IS_WINDOWS = void 0;
+exports.getLinuxOSReleaseInfo = exports.isCacheFeatureAvailable = exports.isGhes = exports.validatePythonVersionFormatForPyPy = exports.writeExactPyPyVersionFile = exports.readExactPyPyVersionFile = exports.getPyPyVersionFromPath = exports.isNightlyKeyword = exports.validateVersion = exports.createSymlinkInFolder = exports.WINDOWS_PLATFORMS = exports.WINDOWS_ARCHS = exports.IS_LINUX = exports.IS_WINDOWS = void 0;
const cache = __importStar(__nccwpck_require__(7799));
const core = __importStar(__nccwpck_require__(2186));
const fs_1 = __importDefault(__nccwpck_require__(7147));
const path = __importStar(__nccwpck_require__(1017));
const semver = __importStar(__nccwpck_require__(1383));
+const exec = __importStar(__nccwpck_require__(1514));
exports.IS_WINDOWS = process.platform === 'win32';
exports.IS_LINUX = process.platform === 'linux';
exports.WINDOWS_ARCHS = ['x86', 'x64'];
@@ -65450,6 +65469,17 @@ function isCacheFeatureAvailable() {
return true;
}
exports.isCacheFeatureAvailable = isCacheFeatureAvailable;
+function getLinuxOSReleaseInfo() {
+ return __awaiter(this, void 0, void 0, function* () {
+ const { stdout, stderr, exitCode } = yield exec.getExecOutput('lsb_release', ['-i', '-r', '-s'], {
+ silent: true
+ });
+ const [osRelease, osVersion] = stdout.trim().split('\n');
+ core.debug(`OS Release: ${osRelease}, Version: ${osVersion}`);
+ return `${osVersion}-${osRelease}`;
+ });
+}
+exports.getLinuxOSReleaseInfo = getLinuxOSReleaseInfo;
/***/ }),
diff --git a/src/cache-distributions/pip-cache.ts b/src/cache-distributions/pip-cache.ts
index 17055ea5..460b097c 100644
--- a/src/cache-distributions/pip-cache.ts
+++ b/src/cache-distributions/pip-cache.ts
@@ -7,7 +7,7 @@ import * as path from 'path';
import os from 'os';
import CacheDistributor from './cache-distributor';
-import {IS_WINDOWS} from '../utils';
+import {getLinuxOSReleaseInfo, IS_LINUX, IS_WINDOWS} from '../utils';
class PipCache extends CacheDistributor {
constructor(
@@ -57,8 +57,17 @@ class PipCache extends CacheDistributor {
protected async computeKeys() {
const hash = await glob.hashFiles(this.cacheDependencyPath);
- const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}-${hash}`;
- const restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}`;
+ let primaryKey = '';
+ let restoreKey = '';
+
+ if (IS_LINUX) {
+ const osRelease = await getLinuxOSReleaseInfo();
+ primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${osRelease}-python-${this.pythonVersion}-${this.packageManager}-${hash}`;
+ restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${osRelease}-python-${this.pythonVersion}-${this.packageManager}`;
+ } else {
+ primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}-${hash}`;
+ restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}`;
+ }
return {
primaryKey,
diff --git a/src/utils.ts b/src/utils.ts
index eb3a1ba6..6eb1388f 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -3,6 +3,7 @@ import * as core from '@actions/core';
import fs from 'fs';
import * as path from 'path';
import * as semver from 'semver';
+import * as exec from '@actions/exec';
export const IS_WINDOWS = process.platform === 'win32';
export const IS_LINUX = process.platform === 'linux';
@@ -119,3 +120,19 @@ export function isCacheFeatureAvailable(): boolean {
return true;
}
+
+export async function getLinuxOSReleaseInfo() {
+ const {stdout, stderr, exitCode} = await exec.getExecOutput(
+ 'lsb_release',
+ ['-i', '-r', '-s'],
+ {
+ silent: true
+ }
+ );
+
+ const [osRelease, osVersion] = stdout.trim().split('\n');
+
+ core.debug(`OS Release: ${osRelease}, Version: ${osVersion}`);
+
+ return `${osVersion}-${osRelease}`;
+}
From 49a521fa062d323a7f2391290b18cf928ddfe90a Mon Sep 17 00:00:00 2001
From: Dmitry Shibanov
Date: Mon, 25 Jul 2022 15:02:06 +0200
Subject: [PATCH 52/77] Fix poetry version (#445)
---
.github/workflows/e2e-cache.yml | 6 ++---
__tests__/cache-restore.test.ts | 6 +++++
__tests__/data/pyproject.toml | 15 ++++++++++++
dist/setup/index.js | 31 ++++++++++++++++++-------
src/cache-distributions/poetry-cache.ts | 24 ++++++++++++++++++-
src/setup-python.ts | 12 +++++-----
src/utils.ts | 5 ++++
7 files changed, 80 insertions(+), 19 deletions(-)
create mode 100644 __tests__/data/pyproject.toml
diff --git a/.github/workflows/e2e-cache.yml b/.github/workflows/e2e-cache.yml
index 0aea4b77..2e903a48 100644
--- a/.github/workflows/e2e-cache.yml
+++ b/.github/workflows/e2e-cache.yml
@@ -72,15 +72,15 @@ jobs:
- uses: actions/checkout@v3
- name: Install poetry
run: pipx install poetry
+ - name: Init pyproject.toml
+ run: mv ./__tests__/data/pyproject.toml .
- name: Setup Python
uses: ./
with:
python-version: ${{ matrix.python-version }}
cache: 'poetry'
- - name: Init pyproject.toml
- run: poetry init -n
- name: Install dependencies
- run: poetry add flake8
+ run: poetry install
python-pip-dependencies-caching-path:
name: Test pip (Python ${{ matrix.python-version}}, ${{ matrix.os }})
diff --git a/__tests__/cache-restore.test.ts b/__tests__/cache-restore.test.ts
index b0d44b8f..8331b812 100644
--- a/__tests__/cache-restore.test.ts
+++ b/__tests__/cache-restore.test.ts
@@ -1,6 +1,7 @@
import * as core from '@actions/core';
import * as cache from '@actions/cache';
import * as exec from '@actions/exec';
+import * as io from '@actions/io';
import {getCacheDistributor} from '../src/cache-distributions/cache-factory';
import * as utils from './../src/utils';
@@ -37,6 +38,9 @@ virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/py
// exec spy
let getExecOutputSpy: jest.SpyInstance;
+ // io spy
+ let whichSpy: jest.SpyInstance;
+
beforeEach(() => {
process.env['RUNNER_OS'] = process.env['RUNNER_OS'] ?? 'linux';
@@ -77,6 +81,8 @@ virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/py
}
);
+ whichSpy = jest.spyOn(io, 'which');
+ whichSpy.mockImplementation(() => '/path/to/python');
getLinuxOSReleaseInfoSpy = jest.spyOn(utils, 'getLinuxOSReleaseInfo');
});
diff --git a/__tests__/data/pyproject.toml b/__tests__/data/pyproject.toml
new file mode 100644
index 00000000..ff4d8bd0
--- /dev/null
+++ b/__tests__/data/pyproject.toml
@@ -0,0 +1,15 @@
+[tool.poetry]
+name = "testactiontasks"
+version = "0.1.0"
+description = ""
+authors = ["Your Name "]
+
+[tool.poetry.dependencies]
+python = "^3.8"
+flake8 = "^4.0.1"
+
+[tool.poetry.dev-dependencies]
+
+[build-system]
+requires = ["poetry-core>=1.0.0"]
+build-backend = "poetry.core.masonry.api"
diff --git a/dist/setup/index.js b/dist/setup/index.js
index dec74449..3d373467 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -64573,9 +64573,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const glob = __importStar(__nccwpck_require__(8090));
+const io = __importStar(__nccwpck_require__(7436));
const path = __importStar(__nccwpck_require__(1017));
const exec = __importStar(__nccwpck_require__(1514));
+const core = __importStar(__nccwpck_require__(2186));
const cache_distributor_1 = __importDefault(__nccwpck_require__(8953));
+const utils_1 = __nccwpck_require__(1314);
class PoetryCache extends cache_distributor_1.default {
constructor(pythonVersion, patterns = '**/poetry.lock') {
super('poetry', patterns);
@@ -64591,6 +64594,17 @@ class PoetryCache extends cache_distributor_1.default {
if (poetryConfig['virtualenvs.in-project'] === true) {
paths.push(path.join(process.cwd(), '.venv'));
}
+ const pythonLocation = yield io.which('python');
+ if (pythonLocation) {
+ core.debug(`pythonLocation is ${pythonLocation}`);
+ const { exitCode, stderr } = yield exec.getExecOutput(`poetry env use ${pythonLocation}`, undefined, { ignoreReturnCode: true });
+ if (exitCode) {
+ utils_1.logWarning(stderr);
+ }
+ }
+ else {
+ utils_1.logWarning('python binaries were not found in PATH');
+ }
return paths;
});
}
@@ -65241,7 +65255,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.logWarning = void 0;
const core = __importStar(__nccwpck_require__(2186));
const finder = __importStar(__nccwpck_require__(9996));
const finderPyPy = __importStar(__nccwpck_require__(4003));
@@ -65277,14 +65290,14 @@ function resolveVersionInput() {
core.info(`Resolved ${versionFile} as ${version}`);
return version;
}
- logWarning("Neither 'python-version' nor 'python-version-file' inputs were supplied. Attempting to find '.python-version' file.");
+ utils_1.logWarning("Neither 'python-version' nor 'python-version-file' inputs were supplied. Attempting to find '.python-version' file.");
versionFile = '.python-version';
if (fs_1.default.existsSync(versionFile)) {
version = fs_1.default.readFileSync(versionFile, 'utf8');
core.info(`Resolved ${versionFile} as ${version}`);
return version;
}
- logWarning(`${versionFile} doesn't exist.`);
+ utils_1.logWarning(`${versionFile} doesn't exist.`);
return version;
}
function run() {
@@ -65332,11 +65345,6 @@ function run() {
}
});
}
-function logWarning(message) {
- const warningPrefix = '[warning]';
- core.info(`${warningPrefix}${message}`);
-}
-exports.logWarning = logWarning;
run();
@@ -65379,7 +65387,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.getLinuxOSReleaseInfo = exports.isCacheFeatureAvailable = exports.isGhes = exports.validatePythonVersionFormatForPyPy = exports.writeExactPyPyVersionFile = exports.readExactPyPyVersionFile = exports.getPyPyVersionFromPath = exports.isNightlyKeyword = exports.validateVersion = exports.createSymlinkInFolder = exports.WINDOWS_PLATFORMS = exports.WINDOWS_ARCHS = exports.IS_LINUX = exports.IS_WINDOWS = void 0;
+exports.logWarning = exports.getLinuxOSReleaseInfo = exports.isCacheFeatureAvailable = exports.isGhes = exports.validatePythonVersionFormatForPyPy = exports.writeExactPyPyVersionFile = exports.readExactPyPyVersionFile = exports.getPyPyVersionFromPath = exports.isNightlyKeyword = exports.validateVersion = exports.createSymlinkInFolder = exports.WINDOWS_PLATFORMS = exports.WINDOWS_ARCHS = exports.IS_LINUX = exports.IS_WINDOWS = void 0;
const cache = __importStar(__nccwpck_require__(7799));
const core = __importStar(__nccwpck_require__(2186));
const fs_1 = __importDefault(__nccwpck_require__(7147));
@@ -65480,6 +65488,11 @@ function getLinuxOSReleaseInfo() {
});
}
exports.getLinuxOSReleaseInfo = getLinuxOSReleaseInfo;
+function logWarning(message) {
+ const warningPrefix = '[warning]';
+ core.info(`${warningPrefix}${message}`);
+}
+exports.logWarning = logWarning;
/***/ }),
diff --git a/src/cache-distributions/poetry-cache.ts b/src/cache-distributions/poetry-cache.ts
index 5e22b5dd..60ecea2b 100644
--- a/src/cache-distributions/poetry-cache.ts
+++ b/src/cache-distributions/poetry-cache.ts
@@ -1,9 +1,11 @@
import * as glob from '@actions/glob';
-import * as os from 'os';
+import * as io from '@actions/io';
import * as path from 'path';
import * as exec from '@actions/exec';
+import * as core from '@actions/core';
import CacheDistributor from './cache-distributor';
+import {logWarning} from '../utils';
class PoetryCache extends CacheDistributor {
constructor(
@@ -28,6 +30,26 @@ class PoetryCache extends CacheDistributor {
paths.push(path.join(process.cwd(), '.venv'));
}
+ const pythonLocation = await io.which('python');
+
+ if (pythonLocation) {
+ core.debug(`pythonLocation is ${pythonLocation}`);
+ const {
+ exitCode,
+ stderr
+ } = await exec.getExecOutput(
+ `poetry env use ${pythonLocation}`,
+ undefined,
+ {ignoreReturnCode: true}
+ );
+
+ if (exitCode) {
+ logWarning(stderr);
+ }
+ } else {
+ logWarning('python binaries were not found in PATH');
+ }
+
return paths;
}
diff --git a/src/setup-python.ts b/src/setup-python.ts
index 23356889..1ebcbac3 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -5,7 +5,12 @@ import * as path from 'path';
import * as os from 'os';
import fs from 'fs';
import {getCacheDistributor} from './cache-distributions/cache-factory';
-import {isCacheFeatureAvailable, IS_LINUX, IS_WINDOWS} from './utils';
+import {
+ isCacheFeatureAvailable,
+ logWarning,
+ IS_LINUX,
+ IS_WINDOWS
+} from './utils';
function isPyPyVersion(versionSpec: string) {
return versionSpec.startsWith('pypy');
@@ -115,9 +120,4 @@ async function run() {
}
}
-export function logWarning(message: string): void {
- const warningPrefix = '[warning]';
- core.info(`${warningPrefix}${message}`);
-}
-
run();
diff --git a/src/utils.ts b/src/utils.ts
index 6eb1388f..7d4fa02e 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -136,3 +136,8 @@ export async function getLinuxOSReleaseInfo() {
return `${osVersion}-${osRelease}`;
}
+
+export function logWarning(message: string): void {
+ const warningPrefix = '[warning]';
+ core.info(`${warningPrefix}${message}`);
+}
From 2f06e9da25e11351919e97ebc9d3cd20dc7208ab Mon Sep 17 00:00:00 2001
From: Dmitry Shibanov
Date: Mon, 25 Jul 2022 16:54:04 +0200
Subject: [PATCH 53/77] Add check-latest functionality (#406)
---
.github/workflows/test-pypy.yml | 33 ++++++
.github/workflows/test-python.yml | 24 +++++
.licenses/npm/@actions/http-client.dep.yml | 32 ------
README.md | 18 ++++
__tests__/find-pypy.test.ts | 117 +++++++++++++++++++--
__tests__/finder.test.ts | 87 +++++++++++++--
__tests__/install-pypy.test.ts | 34 +++++-
action.yml | 3 +
dist/setup/index.js | 66 +++++++++---
src/find-pypy.ts | 34 +++++-
src/find-python.ts | 29 ++++-
src/install-pypy.ts | 8 +-
src/install-python.ts | 29 +++--
src/setup-python.ts | 8 +-
14 files changed, 440 insertions(+), 82 deletions(-)
delete mode 100644 .licenses/npm/@actions/http-client.dep.yml
diff --git a/.github/workflows/test-pypy.yml b/.github/workflows/test-pypy.yml
index 4800662e..de9ba6b7 100644
--- a/.github/workflows/test-pypy.yml
+++ b/.github/workflows/test-pypy.yml
@@ -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
\ No newline at end of file
diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml
index 17709ec5..921449fb 100644
--- a/.github/workflows/test-python.yml
+++ b/.github/workflows/test-python.yml
@@ -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
\ No newline at end of file
diff --git a/.licenses/npm/@actions/http-client.dep.yml b/.licenses/npm/@actions/http-client.dep.yml
deleted file mode 100644
index 43316cbc..00000000
--- a/.licenses/npm/@actions/http-client.dep.yml
+++ /dev/null
@@ -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: []
diff --git a/README.md b/README.md
index 6e178e2f..cb170045 100644
--- a/README.md
+++ b/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.
diff --git a/__tests__/find-pypy.test.ts b/__tests__/find-pypy.test.ts
index 3da9a226..660f23d3 100644
--- a/__tests__/find-pypy.test.ts
+++ b/__tests__/find-pypy.test.ts
@@ -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'
+ );
+ });
});
diff --git a/__tests__/finder.test.ts b/__tests__/finder.test.ts
index 3bd279f1..d2fe775b 100644
--- a/__tests__/finder.test.ts
+++ b/__tests__/finder.test.ts
@@ -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(() => 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(() => 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(() => 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;
}
diff --git a/__tests__/install-pypy.test.ts b/__tests__/install-pypy.test.ts
index cffc90e8..ae7fb4a6 100644
--- a/__tests__/install-pypy.test.ts
+++ b/__tests__/install-pypy.test.ts
@@ -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',
diff --git a/action.yml b/action.yml
index de2a4feb..f4aeb35b 100644
--- a/action.yml
+++ b/action.yml
@@ -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 }}
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 3d373467..f9cb76f1 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -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})`);
}
diff --git a/src/find-pypy.ts b/src/find-pypy.ts
index 3cc3fdd2..20b9821e 100644
--- a/src/find-pypy.ts
+++ b/src/find-pypy.ts
@@ -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
));
}
diff --git a/src/find-python.ts b/src/find-python.ts
index e1add953..4e54a94b 100644
--- a/src/find-python.ts
+++ b/src/find-python.ts
@@ -33,12 +33,34 @@ function binDir(installDir: string): string {
export async function useCpythonVersion(
version: string,
architecture: string,
- updateEnvironment: boolean
+ updateEnvironment: boolean,
+ checkLatest: boolean
): Promise {
+ 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) {
diff --git a/src/install-pypy.ts b/src/install-pypy.ts
index c3718b79..4c49e115 100644
--- a/src/install-pypy.ts
+++ b/src/install-pypy.ts
@@ -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');
diff --git a/src/install-python.ts b/src/install-python.ts
index 397da0cb..6e5c8518 100644
--- a/src/install-python.ts
+++ b/src/install-python.ts
@@ -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 {
- 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 {
+ 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) {
diff --git a/src/setup-python.ts b/src/setup-python.ts
index 1ebcbac3..11ea4056 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -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})`);
From 00d9c42868d28c68834181199e779da29bb4f198 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Mon, 25 Jul 2022 19:42:15 +0200
Subject: [PATCH 54/77] Change part with realted to self-hosted runners
---
docs/advanced-usage.md | 47 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 45 insertions(+), 2 deletions(-)
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index 407d0254..88761e7b 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -412,9 +412,12 @@ GitHub virtual environments are set up in [actions/virtual-environments](https:/
# Using `setup-python` with a self hosted runner
-Python distributions are only available for the same [environments](https://github.com/actions/virtual-environments#available-environments) that GitHub Actions hosted environments are available for. If you are using an unsupported version of Ubuntu such as `19.04` or another Linux distribution such as Fedora, `setup-python` will not work. If you have a supported self-hosted runner and you would like to use `setup-python`, there are a few extra things you need to make sure are set up so that new versions of Python can be downloaded and configured on your runner.
+Python distributions are only available for the same [environments](https://github.com/actions/virtual-environments#available-environments) that GitHub Actions hosted environments are available for. If you are using an unsupported version of Ubuntu such as `19.04` or another Linux distribution such as Fedora, `setup-python` may not work.
-## Windows requirements
+If you have a supported self-hosted runner and you would like to use `setup-python`, there are a few extra things you need to make sure are set up so that new versions of Python can be downloaded and configured on your runner.
+
+
+## Windows
- Your runner needs to be running with administrator privileges so that the appropriate directories and files can be set up when downloading and installing a new version of Python for the first time.
- If your runner is configured as a service, make sure the account that is running the service has the appropriate write permissions so that Python can get installed. The default `NT AUTHORITY\NETWORK SERVICE` should be sufficient.
@@ -422,8 +425,48 @@ Python distributions are only available for the same [environments](https://gith
- MSI installers are used when setting up Python on Windows. A word of caution as MSI installers update registry settings.
- The 3.8 MSI installer for Windows will not let you install another 3.8 version of Python. If `setup-python` fails for a 3.8 version of Python, make sure any previously installed versions are removed by going to "Apps & Features" in the Settings app.
+> By default runner downloads and installs tools into the folder set up by `RUNNER_TOOL_CACHE` environment variable. The environment variable called `AGENT_TOOLSDIRECTORY` can be set to change this location for Windows self-hosted runners.
+
>If you are experiencing problems while configuring Python on your self-hosted runner, turn on [step debugging](https://github.com/actions/toolkit/blob/main/docs/action-debugging.md#step-debug-logs) to see addition logs.
+## Linux
+
+By default runner downloads and installs tools into the folder set up by `RUNNER_TOOL_CACHE` environment variable. The environment variable called `AGENT_TOOLSDIRECTORY` can be set to change this location for Linux self-hosted runners:
+- In the same shell that your runner is using, type `export AGENT_TOOLSDIRECTORY=/path/to/folder`.
+- More permanent way of setting the environment variable is to create an `.env` file in the same directory as your runner and to add `AGENT_TOOLSDIRECTORY=/path/to/folder`. This ensures the variable is always set if your runner is configured as a service.
+
+If you're using non-default tool cache directory be sure that the user starting the runner have write permission to the new tool cache directory folder. To check the current user and group that the runner belongs type `ls -l` inside the runners root directory.
+
+The runner can be granted write access to any directory using a few techniques:
+- The user starting the runner is the owner, and the owner has write permission.
+- The user starting the runner is in the owning group, and the owning group has write permission.
+- All users have write permission.
+One quick way to grant access is to change the user and group of the non-default tool cache folder to be the same as the runners using `chown`:
+`sudo chown runner-user:runner-group /path/to/folder`.
+
+
+> If your runner is configured as a service and you run into problems, make sure the user that the service is running as is correct. For more information, you can [check the status of your self-hosted runner](https://docs.github.com/en/actions/hosting-your-own-runners/configuring-the-self-hosted-runner-application-as-a-service#checking-the-status-of-the-service).
+
+
+## MacOS
+
+ The Python packages for MacOS that are downloaded from `actions/python-versions` are originally compiled from source in `/Users/runner/hostedtoolcache`. Due to the fixed shared library path, these Python packages are non-relocatable and require to be installed only in `/Users/runner/hostedtoolcache`. Before use of `setup-python` on the MacOS self-hosted runner:
+
+ - Create a directory called `/Users/runner/hostedtoolcache`
+ - Change the permissions of `/Users/runner/hostedtoolcache` so that the runner has write access.
+
+You can check the current user and group that the runner belongs to by typing `ls -l` inside the runners root directory.
+The runner can be granted write access to the `/Users/runner/hostedtoolcache` directory using a few techniques:
+ - The user starting the runner is the owner, and the owner has write permission.
+ - The user starting the runner is in the owning group, and the owning group has write permission.
+ - All users have write permission.
+One quick way to grant access is to change the user and group of `/Users/runner/hostedtoolcache` to be the same as the runners using `chown`:
+`sudo chown runner-user:runner-group /Users/runner/hostedtoolcache`
+
+> If your runner is configured as a service and you run into problems, make sure the user that the service is running as is correct. For more information, you can [check the status of your self-hosted runner](https://docs.github.com/en/actions/hosting-your-own-runners/configuring-the-self-hosted-runner-application-as-a-service#checking-the-status-of-the-service).
+
+
+
# Using `setup-python` on GHES
`setup-python` comes pre-installed on the appliance with GHES if Actions is enabled. When dynamically downloading Python distributions, `setup-python` downloads distributions from [`actions/python-versions`](https://github.com/actions/python-versions) on github.com (outside of the appliance). These calls to `actions/python-versions` are made via unauthenticated requests, which are limited to [60 requests per hour per IP](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting). If more requests are made within the time frame, then you will start to see rate-limit errors during download that read `##[error]API rate limit exceeded for...`.
From 889226ae9a8f3aff0dbe4fc78e012072257c3363 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Mon, 25 Jul 2022 19:44:22 +0200
Subject: [PATCH 55/77] Fix typo
---
docs/advanced-usage.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index 88761e7b..0a1a2ac8 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -435,7 +435,7 @@ By default runner downloads and installs tools into the folder set up by `RUNNER
- In the same shell that your runner is using, type `export AGENT_TOOLSDIRECTORY=/path/to/folder`.
- More permanent way of setting the environment variable is to create an `.env` file in the same directory as your runner and to add `AGENT_TOOLSDIRECTORY=/path/to/folder`. This ensures the variable is always set if your runner is configured as a service.
-If you're using non-default tool cache directory be sure that the user starting the runner have write permission to the new tool cache directory folder. To check the current user and group that the runner belongs type `ls -l` inside the runners root directory.
+If you're using non-default tool cache directory be sure that the user starting the runner have write permission to the new tool cache directory. To check the current user and group that the runner belongs type `ls -l` inside the runners root directory.
The runner can be granted write access to any directory using a few techniques:
- The user starting the runner is the owner, and the owner has write permission.
From e147df2e90bcf8cfc14e3204eb6971371601f276 Mon Sep 17 00:00:00 2001
From: Ben S
Date: Mon, 25 Jul 2022 14:22:13 -0400
Subject: [PATCH 56/77] Update README.md
Add a section to advise using only pip instead of poetry.
---
README.md | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/README.md b/README.md
index cb170045..7447c44b 100644
--- a/README.md
+++ b/README.md
@@ -330,6 +330,19 @@ steps:
- run: poetry run pytest
```
+**If you only need poetry install, consider using pip:**
+```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-python@v4
+ with:
+ python-version: '3.9'
+ cache: 'pip'
+ cache-dependency-path: 'poetry.lock'
+- run: pip install .
+- run: pytest
+```
+
**Using wildcard patterns to cache dependencies**
```yaml
steps:
From 0d94a5d71eff739dcec5c2cfed04f676b65f98a3 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Tue, 26 Jul 2022 10:47:51 +0200
Subject: [PATCH 57/77] Fix typo
---
docs/advanced-usage.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index 0a1a2ac8..e3f65437 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -453,12 +453,12 @@ One quick way to grant access is to change the user and group of the non-default
The Python packages for MacOS that are downloaded from `actions/python-versions` are originally compiled from source in `/Users/runner/hostedtoolcache`. Due to the fixed shared library path, these Python packages are non-relocatable and require to be installed only in `/Users/runner/hostedtoolcache`. Before use of `setup-python` on the MacOS self-hosted runner:
- Create a directory called `/Users/runner/hostedtoolcache`
- - Change the permissions of `/Users/runner/hostedtoolcache` so that the runner has write access.
+ - Change the permissions of `/Users/runner/hostedtoolcache` so that the runner has write access
You can check the current user and group that the runner belongs to by typing `ls -l` inside the runners root directory.
The runner can be granted write access to the `/Users/runner/hostedtoolcache` directory using a few techniques:
- - The user starting the runner is the owner, and the owner has write permission.
- - The user starting the runner is in the owning group, and the owning group has write permission.
+ - The user starting the runner is the owner, and the owner has write permission
+ - The user starting the runner is in the owning group, and the owning group has write permission
- All users have write permission.
One quick way to grant access is to change the user and group of `/Users/runner/hostedtoolcache` to be the same as the runners using `chown`:
`sudo chown runner-user:runner-group /Users/runner/hostedtoolcache`
From b2241a475486883b8fbe47e9d23b0b1d6d7ad13b Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Tue, 26 Jul 2022 11:01:07 +0200
Subject: [PATCH 58/77] Change yml and rebuild action
---
action.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/action.yml b/action.yml
index f767b428..f6ff15c4 100644
--- a/action.yml
+++ b/action.yml
@@ -4,7 +4,7 @@ description: 'Set up a specific version of Python and add the command-line tools
author: 'GitHub'
inputs:
python-version:
- description: "Version range or exact version of Python/PyPy to use, using SemVer's version range syntax."
+ description: "Version range or exact version of Python/PyPy to use, using SemVer's version range syntax. Reads from .python-version if unset."
python-version-file:
description: "File containing the Python version to use. Example: .python-version"
cache:
From dd40245e5b4588f5f14a3cebdf97bdc02489ed4d Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Tue, 26 Jul 2022 11:06:43 +0200
Subject: [PATCH 59/77] Fix merge artifacts
---
README.md | 144 -----------------------------------------------------
action.yml | 4 --
2 files changed, 148 deletions(-)
diff --git a/README.md b/README.md
index 43ba10aa..56cfaa0c 100644
--- a/README.md
+++ b/README.md
@@ -47,151 +47,7 @@ The `python-version` input supports the [Semantic Versioning Specification](http
Using `architecture` input it is possible to specify required Python/PyPy interpreter architecture: `x86` or `x64`. If input is not specified the architecture defaults to `x64`.
-<<<<<<< HEAD
## Caching packages dependencies
-=======
-Download and set up the latest stable version of Python (for specified major version):
-```yaml
-steps:
-- uses: actions/checkout@v3
-- uses: actions/setup-python@v4
- with:
- python-version: '3.x'
-- run: python my_script.py
-```
-
-Download and set up PyPy:
-
-```yaml
-jobs:
- build:
- runs-on: ubuntu-latest
- strategy:
- matrix:
- python-version:
- - 'pypy3.7' # the latest available version of PyPy that supports Python 3.7
- - 'pypy3.7-v7.3.3' # Python 3.7 and PyPy 7.3.3
- - 'pypy3.8' # the latest available version of PyPy that supports Python 3.8
- steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-python@v4
- with:
- python-version: ${{ matrix.python-version }}
- - run: python my_script.py
-```
-More details on PyPy syntax and examples of using preview / nightly versions of PyPy can be found in the [Available versions of PyPy](#available-versions-of-pypy) section.
-
-An output is available with the absolute path of the python interpreter executable if you need it:
-```yaml
-jobs:
- build:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-python@v4
- id: cp310
- with:
- python-version: "3.10"
- - run: pipx run --python '${{ steps.cp310.outputs.python-path }}' nox --version
-```
-
->The environment variable `pythonLocation` also becomes available after Python or PyPy installation. It contains the absolute path to the folder where the desired version of Python or PyPy is installed.
-
-# Getting started with Python + Actions
-
-Check out our detailed guide on using [Python with GitHub Actions](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/using-python-with-github-actions).
-
-# Available versions of Python
-
-`setup-python` is able to configure Python from two sources:
-
-- Preinstalled versions of Python in the tools cache on GitHub-hosted runners.
- - For detailed information regarding the available versions of Python that are installed, see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software).
- - For every minor version of Python, expect only the latest patch to be preinstalled.
- - If `3.8.1` is installed for example, and `3.8.2` is released, expect `3.8.1` to be removed and replaced by `3.8.2` in the tools cache.
- - If the exact patch version doesn't matter to you, specifying just the major and minor version will get you the latest preinstalled patch version. In the previous example, the version spec `3.8` will use the `3.8.2` Python version found in the cache.
- - Use `-dev` instead of a patch number (e.g., `3.11-dev`) to install the latest patch version release for a given minor version, *alpha and beta releases included*.
-- Downloadable Python versions from GitHub Releases ([actions/python-versions](https://github.com/actions/python-versions/releases)).
- - All available versions are listed in the [version-manifest.json](https://github.com/actions/python-versions/blob/main/versions-manifest.json) file.
- - If there is a specific version of Python that is not available, you can open an issue here
-
-**Note:** Python versions used in this action are generated in the [python-versions](https://github.com/actions/python-versions) repository. For macOS and Ubuntu images python versions are built from the source code. For Windows the python-versions repository uses installation executable. For more information please refer to the [python-versions](https://github.com/actions/python-versions) repository.
-
- # Available versions of PyPy
-
- `setup-python` is able to configure PyPy from two sources:
-
-- Preinstalled versions of PyPy in the tools cache on GitHub-hosted runners
- - For detailed information regarding the available versions of PyPy that are installed, see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software).
- - For the latest PyPy release, all versions of Python are cached.
- - Cache is updated with a 1-2 week delay. If you specify the PyPy version as `pypy3.7` or `pypy-3.7`, the cached version will be used although a newer version is available. If you need to start using the recently released version right after release, you should specify the exact PyPy version using `pypy3.7-v7.3.3` or `pypy-3.7-v7.3.3`.
-
-- Downloadable PyPy versions from the [official PyPy site](https://downloads.python.org/pypy/).
- - All available versions that we can download are listed in [versions.json](https://downloads.python.org/pypy/versions.json) file.
- - PyPy < 7.3.3 are not available to install on-flight.
- - If some versions are not available, you can open an issue in https://foss.heptapod.net/pypy/pypy/
-
-# Hosted Tool Cache
-
-GitHub hosted runners have a tools cache that comes with a few versions of Python + PyPy already installed. This tools cache helps speed up runs and tool setup by not requiring any new downloads. There is an environment variable called `RUNNER_TOOL_CACHE` on each runner that describes the location of this tools cache and there is where you will find Python and PyPy installed. `setup-python` works by taking a specific version of Python or PyPy in this tools cache and adding it to PATH.
-
-|| Location |
-|------|-------|
-|**Tool Cache Directory** |`RUNNER_TOOL_CACHE`|
-|**Python Tool Cache**|`RUNNER_TOOL_CACHE/Python/*`|
-|**PyPy Tool Cache**|`RUNNER_TOOL_CACHE/PyPy/*`|
-
-GitHub virtual environments are setup in [actions/virtual-environments](https://github.com/actions/virtual-environments). During the setup, the available versions of Python and PyPy are automatically downloaded, setup and documented.
-- Tools cache setup for Ubuntu: [Install-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/linux/scripts/installers/Install-Toolset.ps1) [Configure-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/linux/scripts/installers/Configure-Toolset.ps1)
-- Tools cache setup for Windows: [Install-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/win/scripts/Installers/Install-Toolset.ps1) [Configure-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/win/scripts/Installers/Configure-Toolset.ps1)
-
-# Specifying a Python version
-
-If there is a specific version of Python that you need and you don't want to worry about any potential breaking changes due to patch updates (going from `3.7.5` to `3.7.6` for example), you should specify the exact major, minor, and patch version (such as `3.7.5`)
- - The only downside to this is that set up will take a little longer since the exact version will have to be downloaded if the exact version is not already installed on the runner due to more recent versions.
- - MSI installers are used on Windows for this, so runs will take a little longer to set up vs Mac and Linux.
-
-You should specify only a major and minor version if you are okay with the most recent patch version being used.
- - There will be a single patch version already installed on each runner for every minor version of Python that is supported.
- - The patch version that will be preinstalled, will generally be the latest and every time there is a new patch released, the older version that is preinstalled will be replaced.
- - Using the most recent patch version will result in a very quick setup since no downloads will be required since a locally installed version Python on the runner will be used.
-
-# Specifying a PyPy version
-The version of PyPy should be specified in the format `pypy[-v]` or `pypy-[-v]`.
-The `` parameter is optional and can be skipped. The latest version will be used in this case.
-
-```
-pypy3.7 or pypy-3.7 # the latest available version of PyPy that supports Python 3.7
-pypy3.8 or pypy-3.8 # the latest available version of PyPy that supports Python 3.8
-pypy2.7 or pypy-2.7 # the latest available version of PyPy that supports Python 2.7
-pypy3.7-v7.3.3 or pypy-3.7-v7.3.3 # Python 3.7 and PyPy 7.3.3
-pypy3.7-v7.x or pypy-3.7-v7.x # Python 3.7 and the latest available PyPy 7.x
-pypy3.7-v7.3.3rc1 or pypy-3.7-v7.3.3rc1 # Python 3.7 and preview version of PyPy
-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
->>>>>>> main
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.
diff --git a/action.yml b/action.yml
index fa687c31..f6ff15c4 100644
--- a/action.yml
+++ b/action.yml
@@ -11,11 +11,7 @@ inputs:
description: 'Used to specify a package manager for caching in the default directory. Supported values: pip, pipenv, poetry.'
required: false
architecture:
-<<<<<<< HEAD
description: "The target architecture (x86, x64) of the Python/PyPy interpreter."
-=======
- description: 'The target architecture (x86, x64) of the Python interpreter.'
->>>>>>> main
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
From a624f1f4bc2c35cc36a7efb4177fd0fd795b71b9 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Tue, 26 Jul 2022 11:32:45 +0200
Subject: [PATCH 60/77] Fix grammar in both documents
---
README.md | 14 ++++-----
docs/advanced-usage.md | 68 +++++++++++++++++++++---------------------
2 files changed, 41 insertions(+), 41 deletions(-)
diff --git a/README.md b/README.md
index 56cfaa0c..841d82a7 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@ steps:
python-version: 'pypy3.9'
- run: python my_script.py
```
-The `python-version` input is optional. If not supplied, the action will try to resolve version from the default `.python-version` file. If `.python-version` file doesn't exist Python/PyPy version from the PATH will be used. The default version of Python/PyPy in PATH vary between runners and can be changed unexpectedly so we recommend always use `setup-python`.
+The `python-version` input is optional. If not supplied, the action will try to resolve the version from the default `.python-version` file. If the `.python-version` file doesn't exist Python/PyPy version from the PATH will be used. The default version of Python/PyPy in PATH varies between runners and can be changed unexpectedly so we recommend always using `setup-python`.
The action will first check the local [tool cache](docs/advanced-usage.md#hosted-tool-cache) for a [semver](https://github.com/npm/node-semver#versions) match. If unable to find a specific version in the tool cache, the action will attempt to download a version of Python from [GitHub Releases](https://github.com/actions/python-versions/releases) and for PyPy from the official [PyPy's dist](https://downloads.python.org/pypy/).
@@ -45,15 +45,15 @@ The `python-version` input supports the [Semantic Versioning Specification](http
## Supported architectures
-Using `architecture` input it is possible to specify required Python/PyPy interpreter architecture: `x86` or `x64`. If input is not specified the architecture defaults to `x64`.
+Using `architecture` input it is possible to specify the required Python/PyPy interpreter architecture: `x86` or `x64`. If the input is not specified the architecture defaults to `x64`.
## 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.
-The action defaults to searching for a dependency file (`requirements.txt` for pip, `Pipfile.lock` for pipenv or `poetry.lock` for poetry) in the repository, and uses its hash as a part of the cache key. Input `cache-dependency-path` is used for cases when multiple dependency files are used, they are located in different subdirectories or different files for the hash want to be used.
+The action defaults to searching for a dependency file (`requirements.txt` for pip, `Pipfile.lock` for pipenv or `poetry.lock` for poetry) in the repository, and uses its hash as a part of the cache key. Input `cache-dependency-path` is used for cases when multiple dependency files are used, they are located in different subdirectories or different files for the hash that want to be used.
- - For `pip`, the action will cache global cache directory
+ - For `pip`, the action will cache the global cache directory
- For `pipenv`, the action will cache virtualenv directory
- For `poetry`, the action will cache virtualenv directory
@@ -68,9 +68,9 @@ steps:
cache: 'pip' # caching pip dependencies
- run: pip install -r requirements.txt
```
->**Note:** Restored cache will not be used if the requirements.txt file is not updated for a long time and a newer version of the dependency is available that can lead to an increase in total build time.
+>**Note:** Restored cache will not be used if the requirements.txt file is not updated for a long time and a newer version of the dependency is available which can lead to an increase in total build time.
->The requirements file format allows to specify dependency versions using logical operators (for example chardet>=3.0.4) or specify dependencies without any versions. In this case the pip install -r requirements.txt command will always try to install the latest available package version. To be sure that the cache will be used, please stick to a specific dependency version and update it manually if necessary.
+>The requirements file format allows for specifying dependency versions using logical operators (for example chardet>=3.0.4) or specifying dependencies without any versions. In this case the pip install -r requirements.txt command will always try to install the latest available package version. To be sure that the cache will be used, please stick to a specific dependency version and update it manually if necessary.
See examples of using `cache` and `cache-dependency-path` for `pipenv` and `poetry` in the section: [Caching packages data](docs/advanced-usage.md#caching-packages-data) of the [Advanced usage](docs/advanced-usage.md) guide.
@@ -83,7 +83,7 @@ See examples of using `cache` and `cache-dependency-path` for `pipenv` and `poet
- [Environment variables and action's outputs](docs/advanced-usage.md#environment-variables-and-actions-outputs)
- [Available versions of Python and PyPy](docs/advanced-usage.md#available-versions-of-python-and-pypy)
- [Hosted tool cache](docs/advanced-usage.md#hosted-tool-cache)
-- [Using `setup-python` with a self hosted runner](docs/advanced-usage.md#using-setup-python-with-a-self-hosted-runner)
+- [Using `setup-python` with a self-hosted runner](docs/advanced-usage.md#using-setup-python-with-a-self-hosted-runner)
- [Using `setup-python` on GHES](docs/advanced-usage.md#using-setup-python-on-ghes)
## License
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index e3f65437..4edb5495 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -1,21 +1,21 @@
# Table of contents
-- [Using python-version input](#using-python-version-file-input)
- - [Specifying a Python version](#specifying-a-python-version)
- - [Specifying a PyPy version](#specifying-a-pypy-version)
- - [Matrix Testing](#matrix-testing)
-- [Using python-version-file input](#using-python-version-file-input)
-- [Check latest version](#check-latest-version)
-- [Caching packages data](#caching-packages-data)
-- [Environment variables and action's outputs](#environment-variables-and-actions-outputs)
-- [Available versions of Python and PyPy](#available-versions-of-python-and-pypy)
- - [Python](#python)
- - [PyPy](#pypy)
-- [Hosted tool cache](#hosted-tool-cache)
-- [Using `setup-python` with a self hosted runner](#using-setup-python-with-a-self-hosted-runner)
- - [Windows](#windows)
- - [Linux](#linux)
- - [MacOS](#macos)
-- [Using `setup-python` on GHES](#using-setup-python-on-ghes)
+- [Using python-version input](advanced-usage.md#using-python-version-file-input)
+ - [Specifying a Python version](advanced-usage.md#specifying-a-python-version)
+ - [Specifying a PyPy version](advanced-usage.md#specifying-a-pypy-version)
+ - [Matrix Testing](advanced-usage.md#matrix-testing)
+- [Using python-version-file input](advanced-usage.md#using-python-version-file-input)
+- [Check latest version](advanced-usage.md#check-latest-version)
+- [Caching packages data](advanced-usage.md#caching-packages-data)
+- [Environment variables and action's outputs](advanced-usage.md#environment-variables-and-actions-outputs)
+- [Available versions of Python and PyPy](advanced-usage.md#available-versions-of-python-and-pypy)
+ - [Python](advanced-usage.md#python)
+ - [PyPy](advanced-usage.md#pypy)
+- [Hosted tool cache](advanced-usage.md#hosted-tool-cache)
+- [Using `setup-python` with a self-hosted runner](advanced-usage.md#using-setup-python-with-a-self-hosted-runner)
+ - [Windows](advanced-usage.md#windows)
+ - [Linux](advanced-usage.md#linux)
+ - [MacOS](advanced-usage.md#macos)
+- [Using `setup-python` on GHES](advanced-usage.md#using-setup-python-on-ghes)
# Using python-version input
@@ -33,7 +33,7 @@ steps:
python-version: '3.7.5'
- run: python my_script.py
```
- - The only downside to this is that set up will take a little longer since the exact version will have to be downloaded if the exact version is not already installed on the runner due to more recent versions.
+ - The only downside to this is that set-up will take a little longer since the exact version will have to be downloaded if the exact version is not already installed on the runner due to more recent versions.
- MSI installers are used on Windows for this, so runs will take a little longer to set up vs MacOS and Linux.
You can specify **only a major and minor version** if you are okay with the most recent patch version being used:
@@ -48,9 +48,9 @@ steps:
```
- There will be a single patch version already installed on each runner for every minor version of Python that is supported.
- The patch version that will be preinstalled, will generally be the latest and every time there is a new patch released, the older version that is preinstalled will be replaced.
- - Using the most recent patch version will result in a very quick setup since no downloads will be required since a locally installed version Python on the runner will be used.
+ - Using the most recent patch version will result in a very quick setup since no downloads will be required since a locally installed version of Python on the runner will be used.
-You can specify version with **prerelease tag** to download and set up an accurate pre-release version of Python:
+You can specify the version with **prerelease tag** to download and set up an accurate pre-release version of Python:
```yaml
steps:
@@ -179,9 +179,9 @@ jobs:
# Using python-version-file input
-`setup-python` action has ability to read Python/PyPy version from a version file. `python-version-file` input is used for specifying path to the version file. If `.python-version` file doesn't exist, action will fail with error.
+`setup-python` action can read Python/PyPy version from a version file. `python-version-file` input is used for specifying the path to the version file. If the `.python-version` file doesn't exist, the action will fail with an error.
->In case both `python-version` and `python-version-file` inputs are supplied, `python-version-file` input will be ignored due to its lower priority.
+>In case both `python-version` and `python-version-file` inputs are supplied, the `python-version-file` input will be ignored due to its lower priority.
```yaml
steps:
@@ -285,7 +285,7 @@ steps:
### `python-version`
-Using **python-version** output it's possible to get the installed by action Python/PyPy version. This output is useful when the input `python-version` given as a range (e.g. 3.8.0 - 3.10.0 ), but down in a workflow you need to operate with the exact installed version (e.g. 3.10.1).
+Using **python-version** output it's possible to get the installed by action Python/PyPy version. This output is useful when the input `python-version` is given as a range (e.g. 3.8.0 - 3.10.0 ), but down in a workflow you need to operate with the exact installed version (e.g. 3.10.1).
```yaml
jobs:
@@ -318,7 +318,7 @@ jobs:
```
### `cache-hit`
-**cache-hit** output is available with a boolean value that indicates whether a cache hit occured on the primary key:
+**cache-hit** output is available with a boolean value that indicates whether a cache hit occurred on the primary key:
```
jobs:
@@ -334,7 +334,7 @@ jobs:
- run: echo '${{ steps.cp310.outputs.cache-hit }}' # true if cache-hit occured on the primary key
```
-## Evironment variables
+## Environment variables
These environment variables become available after setup-python action execution:
@@ -373,13 +373,13 @@ Such a requirement on side-effect could be because you don't want your composite
- For detailed information regarding the available versions of Python that are installed, see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software).
- For every minor version of Python, expect only the latest patch to be preinstalled.
- If `3.8.1` is installed for example, and `3.8.2` is released, expect `3.8.1` to be removed and replaced by `3.8.2` in the tool cache.
- - If the exact patch version doesn't matter to you, specifying just the major and minor version will get you the latest preinstalled patch version. In the previous example, the version spec `3.8` will use the `3.8.2` Python version found in the cache.
+ - If the exact patch version doesn't matter to you, specifying just the major and minor versions will get you the latest preinstalled patch version. In the previous example, the version spec `3.8` will use the `3.8.2` Python version found in the cache.
- Use `-dev` instead of a patch number (e.g., `3.11-dev`) to install the latest patch version release for a given minor version, *alpha and beta releases included*.
- Downloadable Python versions from GitHub Releases ([actions/python-versions](https://github.com/actions/python-versions/releases)).
- All available versions are listed in the [version-manifest.json](https://github.com/actions/python-versions/blob/main/versions-manifest.json) file.
- If there is a specific version of Python that is not available, you can open an issue here
->**Note:** Python versions used in this action are generated in the [python-versions](https://github.com/actions/python-versions) repository. For macOS and Ubuntu images python versions are built from the source code. For Windows the python-versions repository uses installation executable. For more information please refer to the [python-versions](https://github.com/actions/python-versions) repository.
+>**Note:** Python versions used in this action are generated in the [python-versions](https://github.com/actions/python-versions) repository. For MacOS and Ubuntu images, python versions are built from the source code. For Windows, the python-versions repository uses installation executable. For more information please refer to the [python-versions](https://github.com/actions/python-versions) repository.
## PyPy
@@ -410,7 +410,7 @@ GitHub virtual environments are set up in [actions/virtual-environments](https:/
- Tool cache setup for Windows: [Install-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/win/scripts/Installers/Install-Toolset.ps1) [Configure-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/win/scripts/Installers/Configure-Toolset.ps1)
-# Using `setup-python` with a self hosted runner
+# Using `setup-python` with a self-hosted runner
Python distributions are only available for the same [environments](https://github.com/actions/virtual-environments#available-environments) that GitHub Actions hosted environments are available for. If you are using an unsupported version of Ubuntu such as `19.04` or another Linux distribution such as Fedora, `setup-python` may not work.
@@ -421,13 +421,13 @@ If you have a supported self-hosted runner and you would like to use `setup-pyth
- Your runner needs to be running with administrator privileges so that the appropriate directories and files can be set up when downloading and installing a new version of Python for the first time.
- If your runner is configured as a service, make sure the account that is running the service has the appropriate write permissions so that Python can get installed. The default `NT AUTHORITY\NETWORK SERVICE` should be sufficient.
-- You need `7zip` installed and added to your `PATH` so that the downloaded versions of Python files can be extracted properly during first-time setup.
+- You need `7zip` installed and added to your `PATH` so that the downloaded versions of Python files can be extracted properly during the first-time setup.
- MSI installers are used when setting up Python on Windows. A word of caution as MSI installers update registry settings.
- The 3.8 MSI installer for Windows will not let you install another 3.8 version of Python. If `setup-python` fails for a 3.8 version of Python, make sure any previously installed versions are removed by going to "Apps & Features" in the Settings app.
> By default runner downloads and installs tools into the folder set up by `RUNNER_TOOL_CACHE` environment variable. The environment variable called `AGENT_TOOLSDIRECTORY` can be set to change this location for Windows self-hosted runners.
->If you are experiencing problems while configuring Python on your self-hosted runner, turn on [step debugging](https://github.com/actions/toolkit/blob/main/docs/action-debugging.md#step-debug-logs) to see addition logs.
+>If you are experiencing problems while configuring Python on your self-hosted runner, turn on [step debugging](https://github.com/actions/toolkit/blob/main/docs/action-debugging.md#step-debug-logs) to see additional logs.
## Linux
@@ -435,7 +435,7 @@ By default runner downloads and installs tools into the folder set up by `RUNNER
- In the same shell that your runner is using, type `export AGENT_TOOLSDIRECTORY=/path/to/folder`.
- More permanent way of setting the environment variable is to create an `.env` file in the same directory as your runner and to add `AGENT_TOOLSDIRECTORY=/path/to/folder`. This ensures the variable is always set if your runner is configured as a service.
-If you're using non-default tool cache directory be sure that the user starting the runner have write permission to the new tool cache directory. To check the current user and group that the runner belongs type `ls -l` inside the runners root directory.
+If you're using a non-default tool cache directory be sure that the user starting the runner has write permission to the new tool cache directory. To check the current user and group that the runner belongs type `ls -l` inside the runner's root directory.
The runner can be granted write access to any directory using a few techniques:
- The user starting the runner is the owner, and the owner has write permission.
@@ -450,12 +450,12 @@ One quick way to grant access is to change the user and group of the non-default
## MacOS
- The Python packages for MacOS that are downloaded from `actions/python-versions` are originally compiled from source in `/Users/runner/hostedtoolcache`. Due to the fixed shared library path, these Python packages are non-relocatable and require to be installed only in `/Users/runner/hostedtoolcache`. Before use of `setup-python` on the MacOS self-hosted runner:
+ The Python packages for MacOS that are downloaded from `actions/python-versions` are originally compiled from the source in `/Users/runner/hostedtoolcache`. Due to the fixed shared library path, these Python packages are non-relocatable and require to be installed only in `/Users/runner/hostedtoolcache`. Before the use of `setup-python` on the MacOS self-hosted runner:
- Create a directory called `/Users/runner/hostedtoolcache`
- Change the permissions of `/Users/runner/hostedtoolcache` so that the runner has write access
-You can check the current user and group that the runner belongs to by typing `ls -l` inside the runners root directory.
+You can check the current user and group that the runner belongs to by typing `ls -l` inside the runner's root directory.
The runner can be granted write access to the `/Users/runner/hostedtoolcache` directory using a few techniques:
- The user starting the runner is the owner, and the owner has write permission
- The user starting the runner is in the owning group, and the owning group has write permission
@@ -469,6 +469,6 @@ One quick way to grant access is to change the user and group of `/Users/runner/
# Using `setup-python` on GHES
-`setup-python` comes pre-installed on the appliance with GHES if Actions is enabled. When dynamically downloading Python distributions, `setup-python` downloads distributions from [`actions/python-versions`](https://github.com/actions/python-versions) on github.com (outside of the appliance). These calls to `actions/python-versions` are made via unauthenticated requests, which are limited to [60 requests per hour per IP](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting). If more requests are made within the time frame, then you will start to see rate-limit errors during download that read `##[error]API rate limit exceeded for...`.
+`setup-python` comes pre-installed on the appliance with GHES if Actions is enabled. When dynamically downloading Python distributions, `setup-python` downloads distributions from [`actions/python-versions`](https://github.com/actions/python-versions) on github.com (outside of the appliance). These calls to `actions/python-versions` are made via unauthenticated requests, which are limited to [60 requests per hour per IP](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting). If more requests are made within the time frame, then you will start to see rate-limit errors during downloading that looks like: `##[error]API rate limit exceeded for...`.
To avoid hitting rate-limit problems, we recommend [setting up your own runner tool cache](https://docs.github.com/en/enterprise-server@2.22/admin/github-actions/managing-access-to-actions-from-githubcom/setting-up-the-tool-cache-on-self-hosted-runners-without-internet-access#about-the-included-setup-actions-and-the-runner-tool-cache).
From b152b04c287bcfebd9fcbe310fd85da74c513089 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Tue, 26 Jul 2022 11:49:26 +0200
Subject: [PATCH 61/77] Fix typo in advanced-usage.md
---
docs/advanced-usage.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index 4edb5495..85d91835 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -179,7 +179,7 @@ jobs:
# Using python-version-file input
-`setup-python` action can read Python/PyPy version from a version file. `python-version-file` input is used for specifying the path to the version file. If the `.python-version` file doesn't exist, the action will fail with an error.
+`setup-python` action can read Python/PyPy version from a version file. `python-version-file` input is used for specifying the path to the version file. If the file that was supplied to `python-version-file` input doesn't exist, the action will fail with error.
>In case both `python-version` and `python-version-file` inputs are supplied, the `python-version-file` input will be ignored due to its lower priority.
From 10b840936c03f6890dd9d74e0c83f718bb986306 Mon Sep 17 00:00:00 2001
From: Leon Wright
Date: Fri, 15 Jul 2022 14:59:28 +0800
Subject: [PATCH 62/77] docs: Agent Tool Cache
This updates and simplies the tool cache documentation to match the implementation in
both and
Relates #459
---
README.md | 21 +++------------------
1 file changed, 3 insertions(+), 18 deletions(-)
diff --git a/README.md b/README.md
index 7447c44b..abb8199c 100644
--- a/README.md
+++ b/README.md
@@ -422,27 +422,12 @@ If you are experiencing problems while configuring Python on your self-hosted ru
### Linux
-- The Python packages that are downloaded from `actions/python-versions` are originally compiled from source in `/opt/hostedtoolcache/` with the [--enable-shared](https://github.com/actions/python-versions/blob/94f04ae6806c6633c82db94c6406a16e17decd5c/builders/ubuntu-python-builder.psm1#L35) flag, which makes them non-relocatable.
-- By default runner downloads and install the tools to `/opt/hostedtoolcache`. The environment variable called `AGENT_TOOLSDIRECTORY` can be set to change this location.
- - In the same shell that your runner is using, type `export AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache`.
- - A more permanent way of setting the environment variable is to create a `.env` file in the same directory as your runner and to add `AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache`. This ensures the variable is always set if your runner is configured as a service.
-- Create a directory called `hostedtoolcache` inside `/opt`.
-- The user starting the runner must have write permission to the `/opt/hostedtoolcache` directory. It is not possible to start the Linux runner with `sudo` and the `/opt` directory usually requires root privileges to write to. Check the current user and group that the runner belongs to by typing `ls -l` inside the runners root directory.
-- The runner can be granted write access to the `/opt/hostedtoolcache` directory using a few techniques:
- - The user starting the runner is the owner, and the owner has write permission.
- - The user starting the runner is in the owning group, and the owning group has write permission.
- - All users have write permission.
-- One quick way to grant access is to change the user and group of `/opt/hostedtoolcache` to be the same as the runners using `chown`.
- - `sudo chown runner-user:runner-group /opt/hostedtoolcache/`.
-- If your runner is configured as a service and you run into problems, make sure the user that the service is running as is correct. For more information, you can [check the status of your self-hosted runner](https://help.github.com/en/actions/hosting-your-own-runners/configuring-the-self-hosted-runner-application-as-a-service#checking-the-status-of-the-service).
+- The Python packages that are downloaded from `actions/python-versions` are originally compiled from source with the [--enable-shared](https://github.com/actions/python-versions/blob/main/builders/ubuntu-python-builder.psm1#L37) flag.
+- By default runner downloads and install the tools to the `RUNNER_TOOL_CACHE` directory, however `AGENT_TOOLSDIRECTORY` can be set to override this location.
### Mac
-- The same setup that applies to `Linux` also applies to `Mac`, just with a different tools cache directory.
-- Create a directory called `/Users/runner/hostedtoolcache`.
-- Set the `AGENT_TOOLSDIRECTORY` environment variable to `/Users/runner/hostedtoolcache`.
-- Change the permissions of `/Users/runner/hostedtoolcache` so that the runner has write access.
-
+- The same setup that applies to `Linux` also applies to `Mac`
# Using Python without `setup-python`
From 9f1915a970ca4e1c3389f899fb4777a3636737d5 Mon Sep 17 00:00:00 2001
From: Leon Wright
Date: Fri, 15 Jul 2022 12:57:51 +0800
Subject: [PATCH 63/77] fix: Self-Hosted Tool Cache
This fixes the tool cache path for self-hosted runners, along
with handling AGENT_TOOLSDIRECTORY for both hosted + self-hosted.
Fixes actions#459
---
dist/setup/index.js | 10 +++-------
src/setup-python.ts | 12 ++++--------
2 files changed, 7 insertions(+), 15 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index f9cb76f1..84778361 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -65340,13 +65340,9 @@ function resolveVersionInput() {
function run() {
var _a;
return __awaiter(this, void 0, void 0, function* () {
- // According to the README windows binaries do not require to be installed
- // in the specific location, but Mac and Linux do
- if (!utils_1.IS_WINDOWS && !((_a = process.env.AGENT_TOOLSDIRECTORY) === null || _a === void 0 ? void 0 : _a.trim())) {
- if (utils_1.IS_LINUX)
- process.env['AGENT_TOOLSDIRECTORY'] = '/opt/hostedtoolcache';
- else
- process.env['AGENT_TOOLSDIRECTORY'] = '/Users/runner/hostedtoolcache';
+ // When setting AGENT_TOOLSDIRECTORY, the actions/tool-cache function find
+ // is not able to find the files cached by actions/python-version.
+ if ((_a = process.env.AGENT_TOOLSDIRECTORY) === null || _a === void 0 ? void 0 : _a.trim()) {
process.env['RUNNER_TOOL_CACHE'] = process.env['AGENT_TOOLSDIRECTORY'];
}
core.debug(`Python is expected to be installed into RUNNER_TOOL_CACHE=${process.env['RUNNER_TOOL_CACHE']}`);
diff --git a/src/setup-python.ts b/src/setup-python.ts
index 11ea4056..0be5acfa 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -7,9 +7,7 @@ import fs from 'fs';
import {getCacheDistributor} from './cache-distributions/cache-factory';
import {
isCacheFeatureAvailable,
- logWarning,
- IS_LINUX,
- IS_WINDOWS
+ logWarning
} from './utils';
function isPyPyVersion(versionSpec: string) {
@@ -68,11 +66,9 @@ function resolveVersionInput(): string {
}
async function run() {
- // According to the README windows binaries do not require to be installed
- // in the specific location, but Mac and Linux do
- if (!IS_WINDOWS && !process.env.AGENT_TOOLSDIRECTORY?.trim()) {
- if (IS_LINUX) process.env['AGENT_TOOLSDIRECTORY'] = '/opt/hostedtoolcache';
- else process.env['AGENT_TOOLSDIRECTORY'] = '/Users/runner/hostedtoolcache';
+ // When setting AGENT_TOOLSDIRECTORY, the actions/tool-cache function find
+ // is not able to find the files cached by actions/python-version.
+ if (process.env.AGENT_TOOLSDIRECTORY?.trim()) {
process.env['RUNNER_TOOL_CACHE'] = process.env['AGENT_TOOLSDIRECTORY'];
}
core.debug(
From 467a9812256033cbdb1dcc41a0be7f40e60cf445 Mon Sep 17 00:00:00 2001
From: Leon Wright
Date: Fri, 22 Jul 2022 16:02:07 +0800
Subject: [PATCH 64/77] feat: Add 'IS_MAC' util
---
dist/setup/index.js | 3 ++-
src/setup-python.ts | 3 ++-
src/utils.ts | 1 +
3 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 84778361..739b53f0 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -65430,6 +65430,7 @@ const semver = __importStar(__nccwpck_require__(1383));
const exec = __importStar(__nccwpck_require__(1514));
exports.IS_WINDOWS = process.platform === 'win32';
exports.IS_LINUX = process.platform === 'linux';
+exports.IS_MAC = process.platform === 'darwin';
exports.WINDOWS_ARCHS = ['x86', 'x64'];
exports.WINDOWS_PLATFORMS = ['win32', 'win64'];
const PYPY_VERSION_FILE = 'PYPY_VERSION';
@@ -65761,4 +65762,4 @@ module.exports = JSON.parse('["ac","com.ac","edu.ac","gov.ac","net.ac","mil.ac",
/******/ module.exports = __webpack_exports__;
/******/
/******/ })()
-;
\ No newline at end of file
+;
diff --git a/src/setup-python.ts b/src/setup-python.ts
index 0be5acfa..bfecd070 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -7,7 +7,8 @@ import fs from 'fs';
import {getCacheDistributor} from './cache-distributions/cache-factory';
import {
isCacheFeatureAvailable,
- logWarning
+ logWarning,
+ IS_MAC
} from './utils';
function isPyPyVersion(versionSpec: string) {
diff --git a/src/utils.ts b/src/utils.ts
index 7d4fa02e..b29c79d6 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -7,6 +7,7 @@ import * as exec from '@actions/exec';
export const IS_WINDOWS = process.platform === 'win32';
export const IS_LINUX = process.platform === 'linux';
+export const IS_MAC = process.platform === 'darwin';
export const WINDOWS_ARCHS = ['x86', 'x64'];
export const WINDOWS_PLATFORMS = ['win32', 'win64'];
const PYPY_VERSION_FILE = 'PYPY_VERSION';
From bc8ee4233085c23ff1e173523bb54ce0fd1a6f6b Mon Sep 17 00:00:00 2001
From: Leon Wright
Date: Fri, 22 Jul 2022 16:03:42 +0800
Subject: [PATCH 65/77] fix: Mac Toolpath
Shared libraries for the Mac python builds are not configured with the
relocatable flag, thus must always be configured with the hosted path.
Relates #459
---
dist/setup/index.js | 15 +++++++++------
src/setup-python.ts | 19 +++++++++++--------
2 files changed, 20 insertions(+), 14 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 739b53f0..713fc0bd 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -65338,14 +65338,17 @@ function resolveVersionInput() {
return version;
}
function run() {
- var _a;
+ var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
- // When setting AGENT_TOOLSDIRECTORY, the actions/tool-cache function find
- // is not able to find the files cached by actions/python-version.
+ if (utils_1.IS_MAC) {
+ process.env['AGENT_TOOLSDIRECTORY'] = '/Users/runner/hostedtoolcache';
+ }
if ((_a = process.env.AGENT_TOOLSDIRECTORY) === null || _a === void 0 ? void 0 : _a.trim()) {
process.env['RUNNER_TOOL_CACHE'] = process.env['AGENT_TOOLSDIRECTORY'];
}
- core.debug(`Python is expected to be installed into RUNNER_TOOL_CACHE=${process.env['RUNNER_TOOL_CACHE']}`);
+ core.debug(`Python is expected to be installed into ${((_b = process.env.AGENT_TOOLSDIRECTORY) === null || _b === void 0 ? void 0 : _b.trim())
+ ? process.env['AGENT_TOOLSDIRECTORY']
+ : process.env['RUNNER_TOOL_CACHE']}`);
try {
const version = resolveVersionInput();
const checkLatest = core.getBooleanInput('check-latest');
@@ -65421,7 +65424,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.logWarning = exports.getLinuxOSReleaseInfo = exports.isCacheFeatureAvailable = exports.isGhes = exports.validatePythonVersionFormatForPyPy = exports.writeExactPyPyVersionFile = exports.readExactPyPyVersionFile = exports.getPyPyVersionFromPath = exports.isNightlyKeyword = exports.validateVersion = exports.createSymlinkInFolder = exports.WINDOWS_PLATFORMS = exports.WINDOWS_ARCHS = exports.IS_LINUX = exports.IS_WINDOWS = void 0;
+exports.logWarning = exports.getLinuxOSReleaseInfo = exports.isCacheFeatureAvailable = exports.isGhes = exports.validatePythonVersionFormatForPyPy = exports.writeExactPyPyVersionFile = exports.readExactPyPyVersionFile = exports.getPyPyVersionFromPath = exports.isNightlyKeyword = exports.validateVersion = exports.createSymlinkInFolder = exports.WINDOWS_PLATFORMS = exports.WINDOWS_ARCHS = exports.IS_MAC = exports.IS_LINUX = exports.IS_WINDOWS = void 0;
const cache = __importStar(__nccwpck_require__(7799));
const core = __importStar(__nccwpck_require__(2186));
const fs_1 = __importDefault(__nccwpck_require__(7147));
@@ -65762,4 +65765,4 @@ module.exports = JSON.parse('["ac","com.ac","edu.ac","gov.ac","net.ac","mil.ac",
/******/ module.exports = __webpack_exports__;
/******/
/******/ })()
-;
+;
\ No newline at end of file
diff --git a/src/setup-python.ts b/src/setup-python.ts
index bfecd070..4728d8f0 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -5,11 +5,7 @@ import * as path from 'path';
import * as os from 'os';
import fs from 'fs';
import {getCacheDistributor} from './cache-distributions/cache-factory';
-import {
- isCacheFeatureAvailable,
- logWarning,
- IS_MAC
-} from './utils';
+import {isCacheFeatureAvailable, logWarning, IS_MAC} from './utils';
function isPyPyVersion(versionSpec: string) {
return versionSpec.startsWith('pypy');
@@ -67,13 +63,20 @@ function resolveVersionInput(): string {
}
async function run() {
- // When setting AGENT_TOOLSDIRECTORY, the actions/tool-cache function find
- // is not able to find the files cached by actions/python-version.
+ if (IS_MAC) {
+ process.env['AGENT_TOOLSDIRECTORY'] = '/Users/runner/hostedtoolcache';
+ }
+
if (process.env.AGENT_TOOLSDIRECTORY?.trim()) {
process.env['RUNNER_TOOL_CACHE'] = process.env['AGENT_TOOLSDIRECTORY'];
}
+
core.debug(
- `Python is expected to be installed into RUNNER_TOOL_CACHE=${process.env['RUNNER_TOOL_CACHE']}`
+ `Python is expected to be installed into ${
+ process.env.AGENT_TOOLSDIRECTORY?.trim()
+ ? process.env['AGENT_TOOLSDIRECTORY']
+ : process.env['RUNNER_TOOL_CACHE']
+ }`
);
try {
const version = resolveVersionInput();
From d5d67707d2d169a376918289347a1e2d5487c70b Mon Sep 17 00:00:00 2001
From: Leon Wright
Date: Sat, 23 Jul 2022 10:19:13 +0800
Subject: [PATCH 66/77] docs: Mac Tool Path
Ensure that the path requirements and reasoning is clear, to reduce
confusion when using self-hosted, or attempting to set an
'AGENT_TOOLSDIRECTORY' environment variable.
---
README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index abb8199c..84cd67b6 100644
--- a/README.md
+++ b/README.md
@@ -427,7 +427,8 @@ If you are experiencing problems while configuring Python on your self-hosted ru
### Mac
-- The same setup that applies to `Linux` also applies to `Mac`
+- The Python packages that are downloaded from `actions/python-versions` are originally compiled from source with the [--enable-shared](https://github.com/actions/python-versions/blob/main/builders/macos-python-builder.psm1#L44) flag, however lack the relocatable flag.
+- Due to the fixed shared library path, only the hosted tool cache of `/Users/runner/hostedtoolcache` is supported, and the path must be writeable by the runner user.
# Using Python without `setup-python`
From 7e39d25e3f2e8f324816db4b0dbb6512eabfff92 Mon Sep 17 00:00:00 2001
From: Leon Wright
Date: Tue, 26 Jul 2022 20:40:49 +0800
Subject: [PATCH 67/77] refactor: Debug message for Python installation path
---
dist/setup/index.js | 6 ++----
src/setup-python.ts | 6 +-----
2 files changed, 3 insertions(+), 9 deletions(-)
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 713fc0bd..f77bae2d 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -65338,7 +65338,7 @@ function resolveVersionInput() {
return version;
}
function run() {
- var _a, _b;
+ var _a;
return __awaiter(this, void 0, void 0, function* () {
if (utils_1.IS_MAC) {
process.env['AGENT_TOOLSDIRECTORY'] = '/Users/runner/hostedtoolcache';
@@ -65346,9 +65346,7 @@ function run() {
if ((_a = process.env.AGENT_TOOLSDIRECTORY) === null || _a === void 0 ? void 0 : _a.trim()) {
process.env['RUNNER_TOOL_CACHE'] = process.env['AGENT_TOOLSDIRECTORY'];
}
- core.debug(`Python is expected to be installed into ${((_b = process.env.AGENT_TOOLSDIRECTORY) === null || _b === void 0 ? void 0 : _b.trim())
- ? process.env['AGENT_TOOLSDIRECTORY']
- : process.env['RUNNER_TOOL_CACHE']}`);
+ core.debug(`Python is expected to be installed into ${process.env['RUNNER_TOOL_CACHE']}`);
try {
const version = resolveVersionInput();
const checkLatest = core.getBooleanInput('check-latest');
diff --git a/src/setup-python.ts b/src/setup-python.ts
index 4728d8f0..d6e6bdaf 100644
--- a/src/setup-python.ts
+++ b/src/setup-python.ts
@@ -72,11 +72,7 @@ async function run() {
}
core.debug(
- `Python is expected to be installed into ${
- process.env.AGENT_TOOLSDIRECTORY?.trim()
- ? process.env['AGENT_TOOLSDIRECTORY']
- : process.env['RUNNER_TOOL_CACHE']
- }`
+ `Python is expected to be installed into ${process.env['RUNNER_TOOL_CACHE']}`
);
try {
const version = resolveVersionInput();
From 81cda82fb03d2b1baeed930115043541a7632672 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Tue, 26 Jul 2022 14:47:59 +0200
Subject: [PATCH 68/77] Fix review points
---
README.md | 8 +++++---
action.yml | 16 ++++++++--------
docs/advanced-usage.md | 16 +++++++---------
3 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/README.md b/README.md
index 841d82a7..282def29 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,9 @@
This action provides the following functionalities for GitHub Actions users:
-- Optionally downloading and installing the requested version of Python/PyPy and adding it to the PATH
+- Optionally installing and adding to PATH a version of Python that is already installed in the runner's tool cache.
+- Downloading, installing and adding to PATH an available version of Python from GitHub Releases ([actions/python-versions](https://github.com/actions/python-versions/releases)) if a specific version is not available in the runner's tool cache.
+- Failing if a specific version of Python is not preinstalled or available for download.
- Optionally caching dependencies for pip, pipenv and poetry
- Registering problem matchers for error output
@@ -18,7 +20,7 @@ See [action.yml](action.yml)
```yaml
steps:
- uses: actions/checkout@v3
-- uses: actions/setup-python@v4 # <- v4 is a major release tag of the action: https://github.com/actions/setup-python/tags
+- uses: actions/setup-python@v4
with:
python-version: '3.10'
- run: python my_script.py
@@ -49,7 +51,7 @@ Using `architecture` input it is possible to specify the required Python/PyPy in
## 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.
+The action has built-in functionality for caching and restoring dependencies. It uses [toolkit/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.
The action defaults to searching for a dependency file (`requirements.txt` for pip, `Pipfile.lock` for pipenv or `poetry.lock` for poetry) in the repository, and uses its hash as a part of the cache key. Input `cache-dependency-path` is used for cases when multiple dependency files are used, they are located in different subdirectories or different files for the hash that want to be used.
diff --git a/action.yml b/action.yml
index f6ff15c4..b812444a 100644
--- a/action.yml
+++ b/action.yml
@@ -1,33 +1,33 @@
---
-name: 'Setup Python'
-description: 'Set up a specific version of Python and add the command-line tools to the PATH.'
-author: 'GitHub'
+name: "Setup Python"
+description: "Set up a specific version of Python and add the command-line tools to the PATH."
+author: "GitHub"
inputs:
python-version:
description: "Version range or exact version of Python/PyPy to use, using SemVer's version range syntax. Reads from .python-version if unset."
python-version-file:
description: "File containing the Python version to use. Example: .python-version"
cache:
- description: 'Used to specify a package manager for caching in the default directory. Supported values: pip, pipenv, poetry.'
+ description: "Used to specify a package manager for caching in the default directory. Supported values: pip, pipenv, poetry."
required: false
architecture:
description: "The target architecture (x86, x64) of the Python/PyPy interpreter."
check-latest:
- description: 'Set this option if you want the action to check for the latest available version that satisfies the version spec.'
+ 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 }}
cache-dependency-path:
- description: 'Used to specify the path to dependency files. Supports wildcards or a list of file names for caching multiple dependencies.'
+ description: "Used to specify the path to dependency files. Supports wildcards or a list of file names for caching multiple dependencies."
update-environment:
- description: 'Set this option if you want the action to update environment variables.'
+ description: "Set this option if you want the action to update environment variables."
default: true
outputs:
python-version:
description: "The installed Python/PyPy version. Useful when given a version range as input."
cache-hit:
- description: 'A boolean value to indicate a cache entry was found'
+ description: "A boolean value to indicate a cache entry was found"
python-path:
description: "The absolute path to the Python/PyPy executable."
runs:
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index 85d91835..c7a3a353 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -1,4 +1,4 @@
-# Table of contents
+# Contents
- [Using python-version input](advanced-usage.md#using-python-version-file-input)
- [Specifying a Python version](advanced-usage.md#specifying-a-python-version)
- [Specifying a PyPy version](advanced-usage.md#specifying-a-pypy-version)
@@ -19,11 +19,9 @@
# Using python-version input
-The `python-version` input is used to specify the required version of Python or PyPy.
-
## Specifying a Python version
-If there is a specific version of Python that you need and you don't want to worry about any potential breaking changes due to patch updates (going from `3.7.5` to `3.7.6` for example), you should specify the **exact major, minor, and patch version** (such as `3.7.5`):
+If there is a specific version of Python that you need and you don't want to worry about any potential breaking changes due to patch updates (going from `3.7.5` to `3.7.6` for example), you should specify the ***exact major, minor, and patch version*** (such as `3.7.5`):
```yaml
steps:
@@ -36,7 +34,7 @@ steps:
- The only downside to this is that set-up will take a little longer since the exact version will have to be downloaded if the exact version is not already installed on the runner due to more recent versions.
- MSI installers are used on Windows for this, so runs will take a little longer to set up vs MacOS and Linux.
-You can specify **only a major and minor version** if you are okay with the most recent patch version being used:
+You can specify ***only a major and minor version*** if you are okay with the most recent patch version being used:
```yaml
steps:
@@ -50,7 +48,7 @@ steps:
- The patch version that will be preinstalled, will generally be the latest and every time there is a new patch released, the older version that is preinstalled will be replaced.
- Using the most recent patch version will result in a very quick setup since no downloads will be required since a locally installed version of Python on the runner will be used.
-You can specify the version with **prerelease tag** to download and set up an accurate pre-release version of Python:
+You can specify the version with ***prerelease tag*** to download and set up an accurate pre-release version of Python:
```yaml
steps:
@@ -61,7 +59,7 @@ steps:
- run: python my_script.py
```
-It's also possible to use **x.y-dev syntax** to download and set up the latest patch version of Python, alpha and beta releases included. (for specified major & minor versions):
+It's also possible to use ***x.y-dev syntax*** to download and set up the latest patch version of Python, alpha and beta releases included. (for specified major & minor versions):
```yaml
steps:
@@ -74,7 +72,7 @@ steps:
You can also use several types of ranges that are specified in [semver](https://github.com/npm/node-semver#ranges), for instance:
-- **[hyphen ranges](https://github.com/npm/node-semver#hyphen-ranges-xyz---abc)** to download and set up the latest available version of Python (includes both pre-release and stable versions):
+- ***[hyphen ranges](https://github.com/npm/node-semver#hyphen-ranges-xyz---abc)*** to download and set up the latest available version of Python (includes both pre-release and stable versions):
```yaml
steps:
@@ -85,7 +83,7 @@ steps:
- run: python my_script.py
```
-- **[x-ranges](https://github.com/npm/node-semver#x-ranges-12x-1x-12-)** to specify the latest stable version of Python (for specified major version):
+- ***[x-ranges](https://github.com/npm/node-semver#x-ranges-12x-1x-12-)*** to specify the latest stable version of Python (for specified major version):
```yaml
steps:
From c6e66a7681a75159e346622594ace087b0be263a Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Tue, 26 Jul 2022 14:51:59 +0200
Subject: [PATCH 69/77] Fix typo
---
docs/advanced-usage.md | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index c7a3a353..878e29cf 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -1,5 +1,5 @@
# Contents
-- [Using python-version input](advanced-usage.md#using-python-version-file-input)
+- [Using python-version input](advanced-usage.md#using-python-version-input)
- [Specifying a Python version](advanced-usage.md#specifying-a-python-version)
- [Specifying a PyPy version](advanced-usage.md#specifying-a-pypy-version)
- [Matrix Testing](advanced-usage.md#matrix-testing)
@@ -21,7 +21,7 @@
## Specifying a Python version
-If there is a specific version of Python that you need and you don't want to worry about any potential breaking changes due to patch updates (going from `3.7.5` to `3.7.6` for example), you should specify the ***exact major, minor, and patch version*** (such as `3.7.5`):
+If there is a specific version of Python that you need and you don't want to worry about any potential breaking changes due to patch updates (going from `3.7.5` to `3.7.6` for example), you should specify the **exact major, minor, and patch version** (such as `3.7.5`):
```yaml
steps:
@@ -34,7 +34,7 @@ steps:
- The only downside to this is that set-up will take a little longer since the exact version will have to be downloaded if the exact version is not already installed on the runner due to more recent versions.
- MSI installers are used on Windows for this, so runs will take a little longer to set up vs MacOS and Linux.
-You can specify ***only a major and minor version*** if you are okay with the most recent patch version being used:
+You can specify **only a major and minor version** if you are okay with the most recent patch version being used:
```yaml
steps:
@@ -48,7 +48,7 @@ steps:
- The patch version that will be preinstalled, will generally be the latest and every time there is a new patch released, the older version that is preinstalled will be replaced.
- Using the most recent patch version will result in a very quick setup since no downloads will be required since a locally installed version of Python on the runner will be used.
-You can specify the version with ***prerelease tag*** to download and set up an accurate pre-release version of Python:
+You can specify the version with **prerelease tag** to download and set up an accurate pre-release version of Python:
```yaml
steps:
@@ -59,7 +59,7 @@ steps:
- run: python my_script.py
```
-It's also possible to use ***x.y-dev syntax*** to download and set up the latest patch version of Python, alpha and beta releases included. (for specified major & minor versions):
+It's also possible to use **x.y-dev syntax** to download and set up the latest patch version of Python, alpha and beta releases included. (for specified major & minor versions):
```yaml
steps:
@@ -72,7 +72,7 @@ steps:
You can also use several types of ranges that are specified in [semver](https://github.com/npm/node-semver#ranges), for instance:
-- ***[hyphen ranges](https://github.com/npm/node-semver#hyphen-ranges-xyz---abc)*** to download and set up the latest available version of Python (includes both pre-release and stable versions):
+- **[hyphen ranges](https://github.com/npm/node-semver#hyphen-ranges-xyz---abc)** to download and set up the latest available version of Python (includes both pre-release and stable versions):
```yaml
steps:
@@ -83,7 +83,7 @@ steps:
- run: python my_script.py
```
-- ***[x-ranges](https://github.com/npm/node-semver#x-ranges-12x-1x-12-)*** to specify the latest stable version of Python (for specified major version):
+- **[x-ranges](https://github.com/npm/node-semver#x-ranges-12x-1x-12-)** to specify the latest stable version of Python (for specified major version):
```yaml
steps:
From fd6f59db224e14d6818f88d8e85f1343a2760d72 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Tue, 26 Jul 2022 14:56:14 +0200
Subject: [PATCH 70/77] Change contents to make them more readable
---
docs/advanced-usage.md | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index 878e29cf..de930e12 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -21,7 +21,7 @@
## Specifying a Python version
-If there is a specific version of Python that you need and you don't want to worry about any potential breaking changes due to patch updates (going from `3.7.5` to `3.7.6` for example), you should specify the **exact major, minor, and patch version** (such as `3.7.5`):
+- If there is a specific version of Python that you need and you don't want to worry about any potential breaking changes due to patch updates (going from `3.7.5` to `3.7.6` for example), you should specify the **exact major, minor, and patch version** (such as `3.7.5`):
```yaml
steps:
@@ -34,7 +34,7 @@ steps:
- The only downside to this is that set-up will take a little longer since the exact version will have to be downloaded if the exact version is not already installed on the runner due to more recent versions.
- MSI installers are used on Windows for this, so runs will take a little longer to set up vs MacOS and Linux.
-You can specify **only a major and minor version** if you are okay with the most recent patch version being used:
+- You can specify **only a major and minor version** if you are okay with the most recent patch version being used:
```yaml
steps:
@@ -48,7 +48,7 @@ steps:
- The patch version that will be preinstalled, will generally be the latest and every time there is a new patch released, the older version that is preinstalled will be replaced.
- Using the most recent patch version will result in a very quick setup since no downloads will be required since a locally installed version of Python on the runner will be used.
-You can specify the version with **prerelease tag** to download and set up an accurate pre-release version of Python:
+- You can specify the version with **prerelease tag** to download and set up an accurate pre-release version of Python:
```yaml
steps:
@@ -59,7 +59,7 @@ steps:
- run: python my_script.py
```
-It's also possible to use **x.y-dev syntax** to download and set up the latest patch version of Python, alpha and beta releases included. (for specified major & minor versions):
+- It's also possible to use **x.y-dev syntax** to download and set up the latest patch version of Python, alpha and beta releases included. (for specified major & minor versions):
```yaml
steps:
@@ -70,9 +70,9 @@ steps:
- run: python my_script.py
```
-You can also use several types of ranges that are specified in [semver](https://github.com/npm/node-semver#ranges), for instance:
+- You can also use several types of ranges that are specified in [semver](https://github.com/npm/node-semver#ranges), for instance:
-- **[hyphen ranges](https://github.com/npm/node-semver#hyphen-ranges-xyz---abc)** to download and set up the latest available version of Python (includes both pre-release and stable versions):
+ - **[hyphen ranges](https://github.com/npm/node-semver#hyphen-ranges-xyz---abc)** to download and set up the latest available version of Python (includes both pre-release and stable versions):
```yaml
steps:
@@ -83,7 +83,7 @@ steps:
- run: python my_script.py
```
-- **[x-ranges](https://github.com/npm/node-semver#x-ranges-12x-1x-12-)** to specify the latest stable version of Python (for specified major version):
+ - **[x-ranges](https://github.com/npm/node-semver#x-ranges-12x-1x-12-)** to specify the latest stable version of Python (for specified major version):
```yaml
steps:
From 853c012a3c7e40881435c8a92898c46539e11860 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Tue, 26 Jul 2022 14:59:35 +0200
Subject: [PATCH 71/77] Change advanced-usage.md
---
docs/advanced-usage.md | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index de930e12..8ddbc8e4 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -23,7 +23,7 @@
- If there is a specific version of Python that you need and you don't want to worry about any potential breaking changes due to patch updates (going from `3.7.5` to `3.7.6` for example), you should specify the **exact major, minor, and patch version** (such as `3.7.5`):
- ```yaml
+```yaml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
@@ -31,12 +31,12 @@ steps:
python-version: '3.7.5'
- run: python my_script.py
```
- - The only downside to this is that set-up will take a little longer since the exact version will have to be downloaded if the exact version is not already installed on the runner due to more recent versions.
- - MSI installers are used on Windows for this, so runs will take a little longer to set up vs MacOS and Linux.
+ - The only downside to this is that set-up will take a little longer since the exact version will have to be downloaded if the exact version is not already installed on the runner due to more recent versions.
+ - MSI installers are used on Windows for this, so runs will take a little longer to set up vs MacOS and Linux.
- You can specify **only a major and minor version** if you are okay with the most recent patch version being used:
- ```yaml
+```yaml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
@@ -44,9 +44,9 @@ steps:
python-version: '3.7'
- run: python my_script.py
```
- - There will be a single patch version already installed on each runner for every minor version of Python that is supported.
- - The patch version that will be preinstalled, will generally be the latest and every time there is a new patch released, the older version that is preinstalled will be replaced.
- - Using the most recent patch version will result in a very quick setup since no downloads will be required since a locally installed version of Python on the runner will be used.
+ - There will be a single patch version already installed on each runner for every minor version of Python that is supported.
+ - The patch version that will be preinstalled, will generally be the latest and every time there is a new patch released, the older version that is preinstalled will be replaced.
+ - Using the most recent patch version will result in a very quick setup since no downloads will be required since a locally installed version of Python on the runner will be used.
- You can specify the version with **prerelease tag** to download and set up an accurate pre-release version of Python:
From fe396d3941d5b4e765fc2fd32ca503e501536e03 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Tue, 26 Jul 2022 15:03:33 +0200
Subject: [PATCH 72/77] Revert changes
---
docs/advanced-usage.md | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index 8ddbc8e4..85c4bdb5 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -21,7 +21,7 @@
## Specifying a Python version
-- If there is a specific version of Python that you need and you don't want to worry about any potential breaking changes due to patch updates (going from `3.7.5` to `3.7.6` for example), you should specify the **exact major, minor, and patch version** (such as `3.7.5`):
+If there is a specific version of Python that you need and you don't want to worry about any potential breaking changes due to patch updates (going from `3.7.5` to `3.7.6` for example), you should specify the **exact major, minor, and patch version** (such as `3.7.5`):
```yaml
steps:
@@ -31,10 +31,11 @@ steps:
python-version: '3.7.5'
- run: python my_script.py
```
- - The only downside to this is that set-up will take a little longer since the exact version will have to be downloaded if the exact version is not already installed on the runner due to more recent versions.
- - MSI installers are used on Windows for this, so runs will take a little longer to set up vs MacOS and Linux.
-- You can specify **only a major and minor version** if you are okay with the most recent patch version being used:
+- The only downside to this is that set-up will take a little longer since the exact version will have to be downloaded if the exact version is not already installed on the runner due to more recent versions.
+- MSI installers are used on Windows for this, so runs will take a little longer to set up vs MacOS and Linux.
+
+You can specify **only a major and minor version** if you are okay with the most recent patch version being used:
```yaml
steps:
@@ -44,11 +45,11 @@ steps:
python-version: '3.7'
- run: python my_script.py
```
- - There will be a single patch version already installed on each runner for every minor version of Python that is supported.
- - The patch version that will be preinstalled, will generally be the latest and every time there is a new patch released, the older version that is preinstalled will be replaced.
- - Using the most recent patch version will result in a very quick setup since no downloads will be required since a locally installed version of Python on the runner will be used.
+- There will be a single patch version already installed on each runner for every minor version of Python that is supported.
+- The patch version that will be preinstalled, will generally be the latest and every time there is a new patch released, the older version that is preinstalled will be replaced.
+- Using the most recent patch version will result in a very quick setup since no downloads will be required since a locally installed version of Python on the runner will be used.
-- You can specify the version with **prerelease tag** to download and set up an accurate pre-release version of Python:
+You can specify the version with **prerelease tag** to download and set up an accurate pre-release version of Python:
```yaml
steps:
@@ -59,7 +60,7 @@ steps:
- run: python my_script.py
```
-- It's also possible to use **x.y-dev syntax** to download and set up the latest patch version of Python, alpha and beta releases included. (for specified major & minor versions):
+It's also possible to use **x.y-dev syntax** to download and set up the latest patch version of Python, alpha and beta releases included. (for specified major & minor versions):
```yaml
steps:
@@ -70,7 +71,7 @@ steps:
- run: python my_script.py
```
-- You can also use several types of ranges that are specified in [semver](https://github.com/npm/node-semver#ranges), for instance:
+You can also use several types of ranges that are specified in [semver](https://github.com/npm/node-semver#ranges), for instance:
- **[hyphen ranges](https://github.com/npm/node-semver#hyphen-ranges-xyz---abc)** to download and set up the latest available version of Python (includes both pre-release and stable versions):
@@ -83,7 +84,7 @@ steps:
- run: python my_script.py
```
- - **[x-ranges](https://github.com/npm/node-semver#x-ranges-12x-1x-12-)** to specify the latest stable version of Python (for specified major version):
+**[x-ranges](https://github.com/npm/node-semver#x-ranges-12x-1x-12-)** to specify the latest stable version of Python (for specified major version):
```yaml
steps:
From 72394d1a3e63e9ea594929a21d057324696cad57 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Tue, 26 Jul 2022 15:04:50 +0200
Subject: [PATCH 73/77] Fix typo
---
docs/advanced-usage.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index 85c4bdb5..43e86bcb 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -73,7 +73,7 @@ steps:
You can also use several types of ranges that are specified in [semver](https://github.com/npm/node-semver#ranges), for instance:
- - **[hyphen ranges](https://github.com/npm/node-semver#hyphen-ranges-xyz---abc)** to download and set up the latest available version of Python (includes both pre-release and stable versions):
+- **[hyphen ranges](https://github.com/npm/node-semver#hyphen-ranges-xyz---abc)** to download and set up the latest available version of Python (includes both pre-release and stable versions):
```yaml
steps:
@@ -84,7 +84,7 @@ steps:
- run: python my_script.py
```
-**[x-ranges](https://github.com/npm/node-semver#x-ranges-12x-1x-12-)** to specify the latest stable version of Python (for specified major version):
+- **[x-ranges](https://github.com/npm/node-semver#x-ranges-12x-1x-12-)** to specify the latest stable version of Python (for specified major version):
```yaml
steps:
From c318b92fd627ecea2e1c2efcd2fd8df4a972d849 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Thu, 28 Jul 2022 09:38:24 +0200
Subject: [PATCH 74/77] Fix review points
---
README.md | 8 ++++----
action.yml | 8 ++++----
docs/advanced-usage.md | 30 +++++++++++++++---------------
3 files changed, 23 insertions(+), 23 deletions(-)
diff --git a/README.md b/README.md
index 282def29..2e2a1193 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
-This action provides the following functionalities for GitHub Actions users:
+This action provides the following functionality for GitHub Actions users:
- Optionally installing and adding to PATH a version of Python that is already installed in the runner's tool cache.
- Downloading, installing and adding to PATH an available version of Python from GitHub Releases ([actions/python-versions](https://github.com/actions/python-versions/releases)) if a specific version is not available in the runner's tool cache.
@@ -35,11 +35,11 @@ steps:
python-version: 'pypy3.9'
- run: python my_script.py
```
-The `python-version` input is optional. If not supplied, the action will try to resolve the version from the default `.python-version` file. If the `.python-version` file doesn't exist Python/PyPy version from the PATH will be used. The default version of Python/PyPy in PATH varies between runners and can be changed unexpectedly so we recommend always using `setup-python`.
+The `python-version` input is optional. If not supplied, the action will try to resolve the version from the default `.python-version` file. If the `.python-version` file doesn't exist Python or PyPy version from the PATH will be used. The default version of Python or PyPy in PATH varies between runners and can be changed unexpectedly so we recommend always using `setup-python`.
The action will first check the local [tool cache](docs/advanced-usage.md#hosted-tool-cache) for a [semver](https://github.com/npm/node-semver#versions) match. If unable to find a specific version in the tool cache, the action will attempt to download a version of Python from [GitHub Releases](https://github.com/actions/python-versions/releases) and for PyPy from the official [PyPy's dist](https://downloads.python.org/pypy/).
-For information regarding locally cached versions of Python/PyPy on GitHub hosted runners, check out [GitHub Actions Virtual Environments](https://github.com/actions/virtual-environments).
+For information regarding locally cached versions of Python or PyPy on GitHub hosted runners, check out [GitHub Actions Virtual Environments](https://github.com/actions/virtual-environments).
## Supported version syntax
@@ -47,7 +47,7 @@ The `python-version` input supports the [Semantic Versioning Specification](http
## Supported architectures
-Using `architecture` input it is possible to specify the required Python/PyPy interpreter architecture: `x86` or `x64`. If the input is not specified the architecture defaults to `x64`.
+Using `architecture` input it is possible to specify the required Python or PyPy interpreter architecture: `x86` or `x64`. If the input is not specified the architecture defaults to `x64`.
## Caching packages dependencies
diff --git a/action.yml b/action.yml
index b812444a..c0fd1d12 100644
--- a/action.yml
+++ b/action.yml
@@ -4,14 +4,14 @@ description: "Set up a specific version of Python and add the command-line tools
author: "GitHub"
inputs:
python-version:
- description: "Version range or exact version of Python/PyPy to use, using SemVer's version range syntax. Reads from .python-version if unset."
+ description: "Version range or exact version of Python or PyPy to use, using SemVer's version range syntax. Reads from .python-version if unset."
python-version-file:
description: "File containing the Python version to use. Example: .python-version"
cache:
description: "Used to specify a package manager for caching in the default directory. Supported values: pip, pipenv, poetry."
required: false
architecture:
- description: "The target architecture (x86, x64) of the Python/PyPy interpreter."
+ description: "The target architecture (x86, x64) of the Python or PyPy 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
@@ -25,11 +25,11 @@ inputs:
default: true
outputs:
python-version:
- description: "The installed Python/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."
cache-hit:
description: "A boolean value to indicate a cache entry was found"
python-path:
- description: "The absolute path to the Python/PyPy executable."
+ description: "The absolute path to the Python or PyPy executable."
runs:
using: 'node16'
main: 'dist/setup/index.js'
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index 43e86bcb..d6365252 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -14,7 +14,7 @@
- [Using `setup-python` with a self-hosted runner](advanced-usage.md#using-setup-python-with-a-self-hosted-runner)
- [Windows](advanced-usage.md#windows)
- [Linux](advanced-usage.md#linux)
- - [MacOS](advanced-usage.md#macos)
+ - [macOS](advanced-usage.md#macos)
- [Using `setup-python` on GHES](advanced-usage.md#using-setup-python-on-ghes)
# Using python-version input
@@ -32,8 +32,8 @@ steps:
- run: python my_script.py
```
-- The only downside to this is that set-up will take a little longer since the exact version will have to be downloaded if the exact version is not already installed on the runner due to more recent versions.
-- MSI installers are used on Windows for this, so runs will take a little longer to set up vs MacOS and Linux.
+- The only downside to this is that setup may take a little longer. If the exact version is not already installed on the runner due to more recent versions, the exact version will have to be downloaded.
+- MSI installers are used on Windows for this, so runs will take a little longer to set up vs macOS and Linux.
You can specify **only a major and minor version** if you are okay with the most recent patch version being used:
@@ -131,7 +131,7 @@ More details on PyPy syntax can be found in the [Available versions of PyPy](#py
## Matrix Testing
-Using `setup-python` it's possible to use [matrix syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix) to install several versions of Python/PyPy:
+Using `setup-python` it's possible to use [matrix syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix) to install several versions of Python or PyPy:
```yaml
jobs:
@@ -178,7 +178,7 @@ jobs:
# Using python-version-file input
-`setup-python` action can read Python/PyPy version from a version file. `python-version-file` input is used for specifying the path to the version file. If the file that was supplied to `python-version-file` input doesn't exist, the action will fail with error.
+`setup-python` action can read Python or PyPy version from a version file. `python-version-file` input is used for specifying the path to the version file. If the file that was supplied to `python-version-file` input doesn't exist, the action will fail with error.
>In case both `python-version` and `python-version-file` inputs are supplied, the `python-version-file` input will be ignored due to its lower priority.
@@ -192,9 +192,9 @@ steps:
```
# 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.
+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 or 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.
+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 or PyPy` version will then be downloaded. Set `check-latest` to `true` if you want the most up-to-date `Python or PyPy` version to always be used.
```yaml
steps:
@@ -205,7 +205,7 @@ steps:
check-latest: true
- run: python my_script.py
```
-> Setting `check-latest` to `true` has performance implications as downloading `Python/PyPy` versions is slower than using cached versions.
+> Setting `check-latest` to `true` has performance implications as downloading `Python or PyPy` versions is slower than using cached versions.
# Caching packages data
@@ -284,7 +284,7 @@ steps:
### `python-version`
-Using **python-version** output it's possible to get the installed by action Python/PyPy version. This output is useful when the input `python-version` is given as a range (e.g. 3.8.0 - 3.10.0 ), but down in a workflow you need to operate with the exact installed version (e.g. 3.10.1).
+Using **python-version** output it's possible to get the installed by action Python or PyPy version. This output is useful when the input `python-version` is given as a range (e.g. 3.8.0 - 3.10.0 ), but down in a workflow you need to operate with the exact installed version (e.g. 3.10.1).
```yaml
jobs:
@@ -301,7 +301,7 @@ jobs:
### `python-path`
-**python-path** output is available with the absolute path of the Python/PyPy interpreter executable if you need it:
+**python-path** output is available with the absolute path of the Python or PyPy interpreter executable if you need it:
```yaml
jobs:
@@ -347,10 +347,10 @@ These environment variables become available after setup-python action execution
## Using `update-environment` flag
The `update-environment` flag defaults to `true`.
-With this setting, the action will add/update environment variables (e.g. `PATH`, `PKG_CONFIG_PATH`, `pythonLocation`) for Python/PyPy to just work out of the box.
+With this setting, the action will add/update environment variables (e.g. `PATH`, `PKG_CONFIG_PATH`, `pythonLocation`) for Python or PyPy to just work out of the box.
If `update-environment` is set to `false`, the action will not add/update environment variables.
-This can prove useful if you want the only side-effect to be to ensure Python/PyPy is installed and rely on the `python-path` output to run executable.
+This can prove useful if you want the only side-effect to be to ensure Python or PyPy is installed and rely on the `python-path` output to run executable.
Such a requirement on side-effect could be because you don't want your composite action messing with your user's workflows.
```yaml
@@ -378,7 +378,7 @@ Such a requirement on side-effect could be because you don't want your composite
- All available versions are listed in the [version-manifest.json](https://github.com/actions/python-versions/blob/main/versions-manifest.json) file.
- If there is a specific version of Python that is not available, you can open an issue here
->**Note:** Python versions used in this action are generated in the [python-versions](https://github.com/actions/python-versions) repository. For MacOS and Ubuntu images, python versions are built from the source code. For Windows, the python-versions repository uses installation executable. For more information please refer to the [python-versions](https://github.com/actions/python-versions) repository.
+>**Note:** Python versions used in this action are generated in the [python-versions](https://github.com/actions/python-versions) repository. For macOS and Ubuntu images, python versions are built from the source code. For Windows, the python-versions repository uses installation executable. For more information please refer to the [python-versions](https://github.com/actions/python-versions) repository.
## PyPy
@@ -447,9 +447,9 @@ One quick way to grant access is to change the user and group of the non-default
> If your runner is configured as a service and you run into problems, make sure the user that the service is running as is correct. For more information, you can [check the status of your self-hosted runner](https://docs.github.com/en/actions/hosting-your-own-runners/configuring-the-self-hosted-runner-application-as-a-service#checking-the-status-of-the-service).
-## MacOS
+## macOS
- The Python packages for MacOS that are downloaded from `actions/python-versions` are originally compiled from the source in `/Users/runner/hostedtoolcache`. Due to the fixed shared library path, these Python packages are non-relocatable and require to be installed only in `/Users/runner/hostedtoolcache`. Before the use of `setup-python` on the MacOS self-hosted runner:
+ The Python packages for macOS that are downloaded from `actions/python-versions` are originally compiled from the source in `/Users/runner/hostedtoolcache`. Due to the fixed shared library path, these Python packages are non-relocatable and require to be installed only in `/Users/runner/hostedtoolcache`. Before the use of `setup-python` on the macOS self-hosted runner:
- Create a directory called `/Users/runner/hostedtoolcache`
- Change the permissions of `/Users/runner/hostedtoolcache` so that the runner has write access
From cfcafa57ec3e74dcd563b5a8ea4a0a330d4ccc33 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Mon, 1 Aug 2022 16:23:57 +0200
Subject: [PATCH 75/77] Fix review points
---
README.md | 4 +---
docs/advanced-usage.md | 40 ++++++++++++++++++++--------------------
2 files changed, 21 insertions(+), 23 deletions(-)
diff --git a/README.md b/README.md
index 2e2a1193..5155ac0d 100644
--- a/README.md
+++ b/README.md
@@ -6,9 +6,7 @@
This action provides the following functionality for GitHub Actions users:
-- Optionally installing and adding to PATH a version of Python that is already installed in the runner's tool cache.
-- Downloading, installing and adding to PATH an available version of Python from GitHub Releases ([actions/python-versions](https://github.com/actions/python-versions/releases)) if a specific version is not available in the runner's tool cache.
-- Failing if a specific version of Python is not preinstalled or available for download.
+- Installing a version of Python or PyPy and (by default) adding it to the PATH
- Optionally caching dependencies for pip, pipenv and poetry
- Registering problem matchers for error output
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index d6365252..7138ba9c 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -1,4 +1,4 @@
-# Contents
+# Advanced Usage
- [Using python-version input](advanced-usage.md#using-python-version-input)
- [Specifying a Python version](advanced-usage.md#specifying-a-python-version)
- [Specifying a PyPy version](advanced-usage.md#specifying-a-pypy-version)
@@ -17,9 +17,9 @@
- [macOS](advanced-usage.md#macos)
- [Using `setup-python` on GHES](advanced-usage.md#using-setup-python-on-ghes)
-# Using python-version input
+## Using the `python-version` input
-## Specifying a Python version
+### Specifying a Python version
If there is a specific version of Python that you need and you don't want to worry about any potential breaking changes due to patch updates (going from `3.7.5` to `3.7.6` for example), you should specify the **exact major, minor, and patch version** (such as `3.7.5`):
@@ -96,7 +96,7 @@ steps:
```
Please refer to the [Advanced range syntax section](https://github.com/npm/node-semver#advanced-range-syntax) of the [semver](https://github.com/npm/node-semver) to check other available range syntaxes.
-## Specifying a PyPy version
+### Specifying a PyPy version
The version of PyPy should be specified in the format `pypy[-v]` or `pypy-[-v]`.
The `-v` parameter is optional and can be skipped. The latest PyPy version will be used in this case.
@@ -129,7 +129,7 @@ jobs:
```
More details on PyPy syntax can be found in the [Available versions of PyPy](#pypy) section.
-## Matrix Testing
+### Matrix Testing
Using `setup-python` it's possible to use [matrix syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix) to install several versions of Python or PyPy:
@@ -176,7 +176,7 @@ jobs:
run: python --version
```
-# Using python-version-file input
+## Using the `python-version-file` input
`setup-python` action can read Python or PyPy version from a version file. `python-version-file` input is used for specifying the path to the version file. If the file that was supplied to `python-version-file` input doesn't exist, the action will fail with error.
@@ -190,7 +190,7 @@ steps:
python-version-file: '.python-version' # Read python version from a file .python-version
- run: python my_script.py
```
-# Check latest version
+## 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 or PyPy` version is always used.
@@ -208,7 +208,7 @@ steps:
> Setting `check-latest` to `true` has performance implications as downloading `Python or PyPy` versions is slower than using cached versions.
-# Caching packages data
+## Caching packages
**Caching pipenv dependencies:**
```yaml
@@ -278,9 +278,9 @@ steps:
- run: pip install -e . -r subdirectory/requirements-dev.txt
```
-# Environment variables and action's outputs
+# Outputs and environment variables
-## Action's outputs
+## Outputs
### `python-version`
@@ -363,8 +363,8 @@ Such a requirement on side-effect could be because you don't want your composite
update-environment: false
- run: ${{ steps.cp310.outputs.python-path }} my_script.py
```
-# Available versions of Python and PyPy
-## Python
+## Available versions of Python and PyPy
+### Python
`setup-python` is able to configure **Python** from two sources:
@@ -380,7 +380,7 @@ Such a requirement on side-effect could be because you don't want your composite
>**Note:** Python versions used in this action are generated in the [python-versions](https://github.com/actions/python-versions) repository. For macOS and Ubuntu images, python versions are built from the source code. For Windows, the python-versions repository uses installation executable. For more information please refer to the [python-versions](https://github.com/actions/python-versions) repository.
-## PyPy
+### PyPy
`setup-python` is able to configure **PyPy** from two sources:
@@ -394,7 +394,7 @@ Such a requirement on side-effect could be because you don't want your composite
- PyPy < 7.3.3 are not available to install on-flight.
- If some versions are not available, you can open an issue in https://foss.heptapod.net/pypy/pypy/
-# Hosted tool cache
+## Hosted tool cache
GitHub hosted runners have a tool cache that comes with a few versions of Python + PyPy already installed. This tool cache helps speed up runs and tool setup by not requiring any new downloads. There is an environment variable called `RUNNER_TOOL_CACHE` on each runner that describes the location of the tool cache with Python and PyPy installed. `setup-python` works by taking a specific version of Python or PyPy from this tool cache and adding it to PATH.
@@ -409,14 +409,14 @@ GitHub virtual environments are set up in [actions/virtual-environments](https:/
- Tool cache setup for Windows: [Install-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/win/scripts/Installers/Install-Toolset.ps1) [Configure-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/win/scripts/Installers/Configure-Toolset.ps1)
-# Using `setup-python` with a self-hosted runner
+## Using `setup-python` with a self-hosted runner
Python distributions are only available for the same [environments](https://github.com/actions/virtual-environments#available-environments) that GitHub Actions hosted environments are available for. If you are using an unsupported version of Ubuntu such as `19.04` or another Linux distribution such as Fedora, `setup-python` may not work.
If you have a supported self-hosted runner and you would like to use `setup-python`, there are a few extra things you need to make sure are set up so that new versions of Python can be downloaded and configured on your runner.
-## Windows
+### Windows
- Your runner needs to be running with administrator privileges so that the appropriate directories and files can be set up when downloading and installing a new version of Python for the first time.
- If your runner is configured as a service, make sure the account that is running the service has the appropriate write permissions so that Python can get installed. The default `NT AUTHORITY\NETWORK SERVICE` should be sufficient.
@@ -428,7 +428,7 @@ If you have a supported self-hosted runner and you would like to use `setup-pyth
>If you are experiencing problems while configuring Python on your self-hosted runner, turn on [step debugging](https://github.com/actions/toolkit/blob/main/docs/action-debugging.md#step-debug-logs) to see additional logs.
-## Linux
+### Linux
By default runner downloads and installs tools into the folder set up by `RUNNER_TOOL_CACHE` environment variable. The environment variable called `AGENT_TOOLSDIRECTORY` can be set to change this location for Linux self-hosted runners:
- In the same shell that your runner is using, type `export AGENT_TOOLSDIRECTORY=/path/to/folder`.
@@ -447,7 +447,7 @@ One quick way to grant access is to change the user and group of the non-default
> If your runner is configured as a service and you run into problems, make sure the user that the service is running as is correct. For more information, you can [check the status of your self-hosted runner](https://docs.github.com/en/actions/hosting-your-own-runners/configuring-the-self-hosted-runner-application-as-a-service#checking-the-status-of-the-service).
-## macOS
+### macOS
The Python packages for macOS that are downloaded from `actions/python-versions` are originally compiled from the source in `/Users/runner/hostedtoolcache`. Due to the fixed shared library path, these Python packages are non-relocatable and require to be installed only in `/Users/runner/hostedtoolcache`. Before the use of `setup-python` on the macOS self-hosted runner:
@@ -466,8 +466,8 @@ One quick way to grant access is to change the user and group of `/Users/runner/
-# Using `setup-python` on GHES
+## Using `setup-python` on GHES
`setup-python` comes pre-installed on the appliance with GHES if Actions is enabled. When dynamically downloading Python distributions, `setup-python` downloads distributions from [`actions/python-versions`](https://github.com/actions/python-versions) on github.com (outside of the appliance). These calls to `actions/python-versions` are made via unauthenticated requests, which are limited to [60 requests per hour per IP](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting). If more requests are made within the time frame, then you will start to see rate-limit errors during downloading that looks like: `##[error]API rate limit exceeded for...`.
-To avoid hitting rate-limit problems, we recommend [setting up your own runner tool cache](https://docs.github.com/en/enterprise-server@2.22/admin/github-actions/managing-access-to-actions-from-githubcom/setting-up-the-tool-cache-on-self-hosted-runners-without-internet-access#about-the-included-setup-actions-and-the-runner-tool-cache).
+To avoid hitting rate-limit problems, we recommend [setting up your own runner tool cache](https://docs.github.com/en/enterprise-server@2.22/admin/github-actions/managing-access-to-actions-from-githubcom/setting-up-the-tool-cache-on-self-hosted-runners-without-internet-access#about-the-included-setup-actions-and-the-runner-tool-cache).
\ No newline at end of file
From c4e98b741b9d2b91a44c958390134fdcb0429533 Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Mon, 1 Aug 2022 16:33:59 +0200
Subject: [PATCH 76/77] Fix broken links
---
README.md | 8 ++++----
docs/advanced-usage.md | 11 +++++++----
2 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/README.md b/README.md
index 5155ac0d..e60f1923 100644
--- a/README.md
+++ b/README.md
@@ -76,11 +76,11 @@ See examples of using `cache` and `cache-dependency-path` for `pipenv` and `poet
## Advanced usage
-- [Using python-version input](docs/advanced-usage.md#using-python-version-input)
-- [Using python-version-file input](docs/advanced-usage.md#using-python-version-file-input)
+- [Using the python-version input](docs/advanced-usage.md#using-the-python-version-input)
+- [Using the python-version-file input](docs/advanced-usage.md#using-the-python-version-file-input)
- [Check latest version](docs/advanced-usage.md#check-latest-version)
-- [Caching packages data](docs/advanced-usage.md#caching-packages-data)
-- [Environment variables and action's outputs](docs/advanced-usage.md#environment-variables-and-actions-outputs)
+- [Caching packages](docs/advanced-usage.md#caching-packages)
+- [Outputs and environment variables](docs/advanced-usage.md#outputs-and-environment-variables)
- [Available versions of Python and PyPy](docs/advanced-usage.md#available-versions-of-python-and-pypy)
- [Hosted tool cache](docs/advanced-usage.md#hosted-tool-cache)
- [Using `setup-python` with a self-hosted runner](docs/advanced-usage.md#using-setup-python-with-a-self-hosted-runner)
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index 7138ba9c..024e8b1e 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -1,12 +1,15 @@
# Advanced Usage
-- [Using python-version input](advanced-usage.md#using-python-version-input)
+- [Using the python-version input](advanced-usage.md#using-the-python-version-input)
- [Specifying a Python version](advanced-usage.md#specifying-a-python-version)
- [Specifying a PyPy version](advanced-usage.md#specifying-a-pypy-version)
- [Matrix Testing](advanced-usage.md#matrix-testing)
-- [Using python-version-file input](advanced-usage.md#using-python-version-file-input)
+- [Using the python-version-file input](advanced-usage.md#using-the-python-version-file-input)
- [Check latest version](advanced-usage.md#check-latest-version)
-- [Caching packages data](advanced-usage.md#caching-packages-data)
-- [Environment variables and action's outputs](advanced-usage.md#environment-variables-and-actions-outputs)
+- [Caching packages](advanced-usage.md#caching-packages)
+- [Outputs and environment variables](advanced-usage.md#outputs-and-environment-variables)
+ - [Outputs](advanced-usage.md#outputs)
+ - [Environment variables](advanced-usage.md#environment-variables)
+ - [Using update-environment flag](advanced-usage.md#using-update-environment-flag)
- [Available versions of Python and PyPy](advanced-usage.md#available-versions-of-python-and-pypy)
- [Python](advanced-usage.md#python)
- [PyPy](advanced-usage.md#pypy)
From 789730b666521111ca6f8cac30ef7f8953d953cb Mon Sep 17 00:00:00 2001
From: IvanZosimov
Date: Mon, 1 Aug 2022 16:44:50 +0200
Subject: [PATCH 77/77] Fix broken links in the text body
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index e60f1923..bc637ed8 100644
--- a/README.md
+++ b/README.md
@@ -41,7 +41,7 @@ For information regarding locally cached versions of Python or PyPy on GitHub ho
## Supported version syntax
-The `python-version` input supports the [Semantic Versioning Specification](https://semver.org/) and some special version notations (e.g. `semver ranges`, `x.y-dev syntax`, etc.), for detailed examples please refer to the section: [Using python-version input](docs/advanced-usage.md#using-python-version-input) of the [Advanced usage](docs/advanced-usage.md) guide.
+The `python-version` input supports the [Semantic Versioning Specification](https://semver.org/) and some special version notations (e.g. `semver ranges`, `x.y-dev syntax`, etc.), for detailed examples please refer to the section: [Using python-version input](docs/advanced-usage.md#using-the-python-version-input) of the [Advanced usage](docs/advanced-usage.md) guide.
## Supported architectures
@@ -72,7 +72,7 @@ steps:
>The requirements file format allows for specifying dependency versions using logical operators (for example chardet>=3.0.4) or specifying dependencies without any versions. In this case the pip install -r requirements.txt command will always try to install the latest available package version. To be sure that the cache will be used, please stick to a specific dependency version and update it manually if necessary.
-See examples of using `cache` and `cache-dependency-path` for `pipenv` and `poetry` in the section: [Caching packages data](docs/advanced-usage.md#caching-packages-data) of the [Advanced usage](docs/advanced-usage.md) guide.
+See examples of using `cache` and `cache-dependency-path` for `pipenv` and `poetry` in the section: [Caching packages](docs/advanced-usage.md#caching-packages) of the [Advanced usage](docs/advanced-usage.md) guide.
## Advanced usage