@rushstack/rush-http-build-cache-plugin 5.97.1-pr3481.18 → 5.98.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.heft/build-cache/jest-cache/haste-map-bae913f9b9aa720eb4deeae0a60a4b27-22ae7f4ce9de4306889d8c05e5cc39b9-f6b1af01a3130057bdfe3d86807211f9 +0 -0
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/{42/Import_42731f0220476b7d949a2d8f3a6f3333 → 12/Import_12af6d2ca109ffba883fc5079062e0e8} +157 -14
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/{c7/commons_c77bee95093c1098b4a591f2dadf398d → 2e/commons_2e52897dfe4222d991674613f5b35882} +1007 -2581
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/{26/package_263c59db6933ba9581588638fb19da5c → 2f/package_2f923ac6ad9bbd4966f8472750ef7770} +2 -2
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/34/PrefixProxyTerminalProvider_34b4603b9c4455de1c3cc05820149fdd +65 -0
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/{58/index_58c57a8f2a96bf6fdf5db35a2e44baa7 → 46/index_46761981528d09d1a0e438f06cd2c548} +7 -2
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/{06/ConfigurationFile_06d7f35feb0bd944d9b9a2a4d9e112c8 → 57/ConfigurationFile_57c950e8ef4673e11bff94304a50823c} +10 -4
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/{fa/rushlib_fa830331d24a41292b5cb91040384188 → 69/rushlib_695f6e29167e91482e2906a8d09b3a5a} +17 -28
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/8a/HttpBuildCacheProvidertest_8a1598e1f1b42d6933964acfb7612893 +116 -0
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/8a/HttpBuildCacheProvidertest_8a1598e1f1b42d6933964acfb7612893.map +1 -0
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/a3/RushHttpBuildCachePlugin_a3e8a9bb172ff361907e770dcf3268be +1551 -0
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/a3/RushHttpBuildCachePlugin_a3e8a9bb172ff361907e770dcf3268be.map +1 -0
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/{c2/Async_c2ea5cc2edc0a460dcf394ef8277e88e → b4/Async_b43c9d64ab6a035dbce65b9f1a28e166} +78 -2
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/ba/TerminalWritable_ba71b4b7bfe6a26c85f4fd0245057a0a +54 -0
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/ce/index_ce3464019fb882539ee9a6f3e36e615a +2 -2
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/ce/index_ce3464019fb882539ee9a6f3e36e615a.map +1 -1
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/{5d/Text_5da85b5db9a2f06bbe29cdcd91e6fbca → df/Text_df57ddd200e4237e617fc183dcb5fe67} +7 -1
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/{e5/HttpBuildCacheProvider_e53bd002cf44ae62693f20b8c4682941 → ec/HttpBuildCacheProvider_ecceab34e8340fa24dde11b618ffa8a4} +1210 -909
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/ec/HttpBuildCacheProvider_ecceab34e8340fa24dde11b618ffa8a4.map +1 -0
- package/.heft/build-cache/jest-cache/perf-cache-bae913f9b9aa720eb4deeae0a60a4b27-da39a3ee5e6b4b0d3255bfef95601890 +1 -1
- package/.rush/temp/operation/_phase_build/state.json +1 -1
- package/.rush/temp/operation/_phase_test/all.log +29 -0
- package/.rush/temp/operation/_phase_test/state.json +1 -1
- package/.rush/temp/package-deps__phase_build.json +5 -5
- package/.rush/temp/package-deps__phase_test.json +5 -5
- package/.rush/temp/rushstack+rush-http-build-cache-plugin-_phase_build-08118e08afc6d454e5623f20498fd64b5e3e9051.log +10 -0
- package/.rush/temp/shrinkwrap-deps.json +10 -10
- package/lib/HttpBuildCacheProvider.d.ts +2 -0
- package/lib/HttpBuildCacheProvider.d.ts.map +1 -1
- package/lib/HttpBuildCacheProvider.js +26 -7
- package/lib/HttpBuildCacheProvider.js.map +1 -1
- package/lib/RushHttpBuildCachePlugin.d.ts.map +1 -1
- package/lib/RushHttpBuildCachePlugin.js +28 -4
- package/lib/RushHttpBuildCachePlugin.js.map +1 -1
- package/lib/test/HttpBuildCacheProvider.test.d.ts.map +1 -0
- package/lib/{HttpBuildCacheProvider.test.js → test/HttpBuildCacheProvider.test.js} +46 -3
- package/lib/test/HttpBuildCacheProvider.test.js.map +1 -0
- package/package.json +6 -6
- package/rush-logs/rush-http-build-cache-plugin._phase_build.log +4 -23
- package/rush-logs/rush-http-build-cache-plugin._phase_test.log +16 -16
- package/src/HttpBuildCacheProvider.ts +36 -7
- package/src/RushHttpBuildCachePlugin.ts +23 -28
- package/src/test/HttpBuildCacheProvider.test.ts +115 -0
- package/temp/coverage/clover.xml +117 -109
- package/temp/coverage/coverage-final.json +2 -2
- package/temp/coverage/lcov-report/HttpBuildCacheProvider.ts.html +166 -79
- package/temp/coverage/lcov-report/RushHttpBuildCachePlugin.ts.html +29 -44
- package/temp/coverage/lcov-report/index.html +24 -24
- package/temp/coverage/lcov-report/index.ts.html +1 -1
- package/temp/coverage/lcov.info +236 -218
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/e5/HttpBuildCacheProvider_e53bd002cf44ae62693f20b8c4682941.map +0 -1
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/e6/RushHttpBuildCachePlugin_e69b4b7cd4f95aa49455690c88f00247 +0 -362
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/e6/RushHttpBuildCachePlugin_e69b4b7cd4f95aa49455690c88f00247.map +0 -1
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/f7/HttpBuildCacheProvidertest_f710af633835df558cad54cb165c14fa +0 -73
- package/.heft/build-cache/jest-cache/jest-transform-cache-bae913f9b9aa720eb4deeae0a60a4b27-474488b31a4a940a3990e9eaf06f1647/f7/HttpBuildCacheProvidertest_f710af633835df558cad54cb165c14fa.map +0 -1
- package/.rush/temp/rushstack+rush-http-build-cache-plugin-_phase_build-5e3cfa01506c2ac77af487ee9732b935a5bbe122.log +0 -27
- package/lib/HttpBuildCacheProvider.test.d.ts.map +0 -1
- package/lib/HttpBuildCacheProvider.test.js.map +0 -1
- package/src/HttpBuildCacheProvider.test.ts +0 -58
- /package/lib/{HttpBuildCacheProvider.test.d.ts → test/HttpBuildCacheProvider.test.d.ts} +0 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
3
|
+
// See LICENSE in the project root for license information.
|
|
2
4
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
5
|
if (k2 === undefined) k2 = k;
|
|
4
6
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -27,9 +29,9 @@ jest.mock('node-fetch', function () {
|
|
|
27
29
|
return Object.assign(jest.fn(), jest.requireActual('node-fetch'));
|
|
28
30
|
});
|
|
29
31
|
const node_fetch_1 = __importStar(require("node-fetch"));
|
|
30
|
-
const HttpBuildCacheProvider_1 = require("./HttpBuildCacheProvider");
|
|
31
32
|
const rush_sdk_1 = require("@rushstack/rush-sdk");
|
|
32
33
|
const node_core_library_1 = require("@rushstack/node-core-library");
|
|
34
|
+
const HttpBuildCacheProvider_1 = require("../HttpBuildCacheProvider");
|
|
33
35
|
const EXAMPLE_OPTIONS = {
|
|
34
36
|
url: 'https://buildcache.example.acme.com',
|
|
35
37
|
tokenHandler: {
|
|
@@ -39,7 +41,8 @@ const EXAMPLE_OPTIONS = {
|
|
|
39
41
|
uploadMethod: 'POST',
|
|
40
42
|
isCacheWriteAllowed: false,
|
|
41
43
|
pluginName: 'example-plugin',
|
|
42
|
-
rushProjectRoot: '/repo'
|
|
44
|
+
rushProjectRoot: '/repo',
|
|
45
|
+
minHttpRetryDelayMs: 1
|
|
43
46
|
};
|
|
44
47
|
describe('HttpBuildCacheProvider', () => {
|
|
45
48
|
let terminalBuffer;
|
|
@@ -59,7 +62,8 @@ describe('HttpBuildCacheProvider', () => {
|
|
|
59
62
|
}));
|
|
60
63
|
const result = await provider.tryGetCacheEntryBufferByIdAsync(terminal, 'some-key');
|
|
61
64
|
expect(result).toBe(undefined);
|
|
62
|
-
expect(node_fetch_1.default).
|
|
65
|
+
expect(node_fetch_1.default).toHaveBeenCalledTimes(1);
|
|
66
|
+
expect(node_fetch_1.default).toHaveBeenNthCalledWith(1, 'https://buildcache.example.acme.com/some-key', {
|
|
63
67
|
body: undefined,
|
|
64
68
|
headers: {},
|
|
65
69
|
method: 'GET',
|
|
@@ -67,6 +71,45 @@ describe('HttpBuildCacheProvider', () => {
|
|
|
67
71
|
});
|
|
68
72
|
expect(terminalBuffer.getWarningOutput()).toMatchInlineSnapshot(`"Error getting cache entry: Error: Credentials for https://buildcache.example.acme.com/ have not been provided.[n]In CI, verify that RUSH_BUILD_CACHE_CREDENTIAL contains a valid Authorization header value.[n][n]For local developers, run:[n][n] rush update-cloud-credentials --interactive[n][n]"`);
|
|
69
73
|
});
|
|
74
|
+
it('attempts up to 3 times to download a cache entry', async () => {
|
|
75
|
+
jest.spyOn(rush_sdk_1.EnvironmentConfiguration, 'buildCacheCredential', 'get').mockReturnValue(undefined);
|
|
76
|
+
const session = {};
|
|
77
|
+
const provider = new HttpBuildCacheProvider_1.HttpBuildCacheProvider(EXAMPLE_OPTIONS, session);
|
|
78
|
+
mocked(node_fetch_1.default).mockResolvedValueOnce(new node_fetch_1.Response('InternalServiceError', {
|
|
79
|
+
status: 500,
|
|
80
|
+
statusText: 'InternalServiceError'
|
|
81
|
+
}));
|
|
82
|
+
mocked(node_fetch_1.default).mockResolvedValueOnce(new node_fetch_1.Response('ServiceUnavailable', {
|
|
83
|
+
status: 503,
|
|
84
|
+
statusText: 'ServiceUnavailable'
|
|
85
|
+
}));
|
|
86
|
+
mocked(node_fetch_1.default).mockResolvedValueOnce(new node_fetch_1.Response('BadGateway', {
|
|
87
|
+
status: 504,
|
|
88
|
+
statusText: 'BadGateway'
|
|
89
|
+
}));
|
|
90
|
+
const result = await provider.tryGetCacheEntryBufferByIdAsync(terminal, 'some-key');
|
|
91
|
+
expect(result).toBe(undefined);
|
|
92
|
+
expect(node_fetch_1.default).toHaveBeenCalledTimes(3);
|
|
93
|
+
expect(node_fetch_1.default).toHaveBeenNthCalledWith(1, 'https://buildcache.example.acme.com/some-key', {
|
|
94
|
+
body: undefined,
|
|
95
|
+
headers: {},
|
|
96
|
+
method: 'GET',
|
|
97
|
+
redirect: 'follow'
|
|
98
|
+
});
|
|
99
|
+
expect(node_fetch_1.default).toHaveBeenNthCalledWith(2, 'https://buildcache.example.acme.com/some-key', {
|
|
100
|
+
body: undefined,
|
|
101
|
+
headers: {},
|
|
102
|
+
method: 'GET',
|
|
103
|
+
redirect: 'follow'
|
|
104
|
+
});
|
|
105
|
+
expect(node_fetch_1.default).toHaveBeenNthCalledWith(3, 'https://buildcache.example.acme.com/some-key', {
|
|
106
|
+
body: undefined,
|
|
107
|
+
headers: {},
|
|
108
|
+
method: 'GET',
|
|
109
|
+
redirect: 'follow'
|
|
110
|
+
});
|
|
111
|
+
expect(terminalBuffer.getWarningOutput()).toMatchInlineSnapshot(`"Could not get cache entry: HTTP 504: BadGateway[n]"`);
|
|
112
|
+
});
|
|
70
113
|
});
|
|
71
114
|
});
|
|
72
115
|
//# sourceMappingURL=HttpBuildCacheProvider.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpBuildCacheProvider.test.js","sourceRoot":"","sources":["../../src/test/HttpBuildCacheProvider.test.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\njest.mock('node-fetch', function () {\n return Object.assign(jest.fn(), jest.requireActual('node-fetch'));\n});\n\nimport fetch, { Response } from 'node-fetch';\nimport { RushSession, EnvironmentConfiguration } from '@rushstack/rush-sdk';\nimport { StringBufferTerminalProvider, Terminal } from '@rushstack/node-core-library';\n\nimport { HttpBuildCacheProvider } from '../HttpBuildCacheProvider';\n\nconst EXAMPLE_OPTIONS = {\n url: 'https://buildcache.example.acme.com',\n tokenHandler: {\n exec: 'node',\n args: ['tokenHandler.js']\n },\n uploadMethod: 'POST',\n isCacheWriteAllowed: false,\n pluginName: 'example-plugin',\n rushProjectRoot: '/repo',\n minHttpRetryDelayMs: 1\n};\n\ndescribe('HttpBuildCacheProvider', () => {\n let terminalBuffer: StringBufferTerminalProvider;\n let terminal!: Terminal;\n\n beforeEach(() => {\n terminalBuffer = new StringBufferTerminalProvider();\n terminal = new Terminal(terminalBuffer);\n });\n\n describe('tryGetCacheEntryBufferByIdAsync', () => {\n it('prints warning if read credentials are not available', async () => {\n jest.spyOn(EnvironmentConfiguration, 'buildCacheCredential', 'get').mockReturnValue(undefined);\n\n const session: RushSession = {} as RushSession;\n const provider = new HttpBuildCacheProvider(EXAMPLE_OPTIONS, session);\n\n mocked(fetch).mockResolvedValue(\n new Response('Unauthorized', {\n status: 401,\n statusText: 'Unauthorized'\n })\n );\n\n const result = await provider.tryGetCacheEntryBufferByIdAsync(terminal, 'some-key');\n expect(result).toBe(undefined);\n expect(fetch).toHaveBeenCalledTimes(1);\n expect(fetch).toHaveBeenNthCalledWith(1, 'https://buildcache.example.acme.com/some-key', {\n body: undefined,\n headers: {},\n method: 'GET',\n redirect: 'follow'\n });\n expect(terminalBuffer.getWarningOutput()).toMatchInlineSnapshot(\n `\"Error getting cache entry: Error: Credentials for https://buildcache.example.acme.com/ have not been provided.[n]In CI, verify that RUSH_BUILD_CACHE_CREDENTIAL contains a valid Authorization header value.[n][n]For local developers, run:[n][n] rush update-cloud-credentials --interactive[n][n]\"`\n );\n });\n\n it('attempts up to 3 times to download a cache entry', async () => {\n jest.spyOn(EnvironmentConfiguration, 'buildCacheCredential', 'get').mockReturnValue(undefined);\n\n const session: RushSession = {} as RushSession;\n const provider = new HttpBuildCacheProvider(EXAMPLE_OPTIONS, session);\n\n mocked(fetch).mockResolvedValueOnce(\n new Response('InternalServiceError', {\n status: 500,\n statusText: 'InternalServiceError'\n })\n );\n mocked(fetch).mockResolvedValueOnce(\n new Response('ServiceUnavailable', {\n status: 503,\n statusText: 'ServiceUnavailable'\n })\n );\n mocked(fetch).mockResolvedValueOnce(\n new Response('BadGateway', {\n status: 504,\n statusText: 'BadGateway'\n })\n );\n\n const result = await provider.tryGetCacheEntryBufferByIdAsync(terminal, 'some-key');\n expect(result).toBe(undefined);\n expect(fetch).toHaveBeenCalledTimes(3);\n expect(fetch).toHaveBeenNthCalledWith(1, 'https://buildcache.example.acme.com/some-key', {\n body: undefined,\n headers: {},\n method: 'GET',\n redirect: 'follow'\n });\n expect(fetch).toHaveBeenNthCalledWith(2, 'https://buildcache.example.acme.com/some-key', {\n body: undefined,\n headers: {},\n method: 'GET',\n redirect: 'follow'\n });\n expect(fetch).toHaveBeenNthCalledWith(3, 'https://buildcache.example.acme.com/some-key', {\n body: undefined,\n headers: {},\n method: 'GET',\n redirect: 'follow'\n });\n expect(terminalBuffer.getWarningOutput()).toMatchInlineSnapshot(\n `\"Could not get cache entry: HTTP 504: BadGateway[n]\"`\n );\n });\n });\n});\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rushstack/rush-http-build-cache-plugin",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.98.0",
|
|
4
4
|
"description": "Rush plugin for generic HTTP cloud build cache",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -14,17 +14,17 @@
|
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"https-proxy-agent": "~5.0.0",
|
|
16
16
|
"node-fetch": "2.6.7",
|
|
17
|
-
"@rushstack/node-core-library": "3.
|
|
18
|
-
"@rushstack/rush-sdk": "5.
|
|
17
|
+
"@rushstack/node-core-library": "3.59.0",
|
|
18
|
+
"@rushstack/rush-sdk": "5.98.0"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/heft-jest": "1.0.1",
|
|
22
22
|
"@types/node": "14.18.36",
|
|
23
23
|
"@types/node-fetch": "2.6.2",
|
|
24
|
-
"@microsoft/rush-lib": "5.
|
|
24
|
+
"@microsoft/rush-lib": "5.98.0",
|
|
25
25
|
"@rushstack/eslint-config": "3.2.0",
|
|
26
|
-
"@rushstack/heft": "0.50.
|
|
27
|
-
"@rushstack/heft-node-rig": "1.12.
|
|
26
|
+
"@rushstack/heft": "0.50.5",
|
|
27
|
+
"@rushstack/heft-node-rig": "1.12.11"
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
30
|
"build": "heft build --clean",
|
|
@@ -1,24 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
Build cache hit.
|
|
2
|
+
Clearing cached folders: dist, lib, lib-commonjs, temp
|
|
3
|
+
Successfully restored output from the build cache.
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
Using rig configuration from ./node_modules/@rushstack/heft-node-rig/profiles/default
|
|
6
|
-
Starting build
|
|
7
|
-
---- Clean started ----
|
|
8
|
-
---- Clean finished (2ms) ----
|
|
9
|
-
---- Pre-compile started ----
|
|
10
|
-
---- Pre-compile finished (0ms) ----
|
|
11
|
-
---- Compile started ----
|
|
12
|
-
[copy-static-assets] Copied 1 file and linked 0 files in 12ms
|
|
13
|
-
[typescript] Using TypeScript version 4.8.4
|
|
14
|
-
---- Compile finished (5243ms) ----
|
|
15
|
-
---- Bundle started ----
|
|
16
|
-
---- Bundle finished (1ms) ----
|
|
17
|
-
---- Post-build started ----
|
|
18
|
-
---- Post-build finished (2ms) ----
|
|
19
|
-
-------------------- Finished (5.609s) --------------------
|
|
20
|
-
Project: @rushstack/rush-http-build-cache-plugin@5.97.1-pr3481.18
|
|
21
|
-
Heft version: 0.50.0
|
|
22
|
-
Node version: v14.21.3
|
|
23
|
-
Caching build output folders: lib
|
|
24
|
-
Successfully set cache entry.
|
|
5
|
+
Restoring cached log file at /home/vsts/work/1/s/rush-plugins/rush-http-build-cache-plugin/.rush/temp/operation/_phase_build/all.log
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
This project does not define the caching behavior of the "_phase:test" command, so caching has been disabled.
|
|
1
2
|
Invoking: heft test --no-build --production
|
|
2
3
|
Using local Heft from /home/vsts/work/1/s/rush-plugins/rush-http-build-cache-plugin/node_modules/@rushstack/heft
|
|
3
4
|
|
|
@@ -7,23 +8,22 @@ Starting test
|
|
|
7
8
|
[jest] Using Jest version 29.5.0
|
|
8
9
|
|
|
9
10
|
Run start. 1 test suite
|
|
10
|
-
START src/HttpBuildCacheProvider.test.ts
|
|
11
|
-
PASS src/HttpBuildCacheProvider.test.ts (duration:
|
|
11
|
+
START src/test/HttpBuildCacheProvider.test.ts
|
|
12
|
+
PASS src/test/HttpBuildCacheProvider.test.ts (duration: 0.693s, 2 passed, 0 failed)
|
|
12
13
|
|
|
13
14
|
Tests finished:
|
|
14
|
-
Successes:
|
|
15
|
+
Successes: 2
|
|
15
16
|
Failures: 0
|
|
16
|
-
Total:
|
|
17
|
-
|
|
18
|
-
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
|
|
19
|
-
|
|
20
|
-
All files |
|
|
21
|
-
HttpBuildCacheProvider.ts |
|
|
22
|
-
RushHttpBuildCachePlugin.ts | 0 | 100 | 0 | 0 |
|
|
23
|
-
index.ts | 0 | 100 | 100 | 0 | 1-3
|
|
24
|
-
|
|
25
|
-
-------------------- Finished (
|
|
26
|
-
Project: @rushstack/rush-http-build-cache-plugin@5.97.1
|
|
27
|
-
Heft version: 0.50.
|
|
17
|
+
Total: 2
|
|
18
|
+
-----------------------------|---------|----------|---------|---------|----------------------------------------------------------------------------
|
|
19
|
+
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
|
|
20
|
+
-----------------------------|---------|----------|---------|---------|----------------------------------------------------------------------------
|
|
21
|
+
All files | 53.23 | 45.55 | 47.82 | 53.23 |
|
|
22
|
+
HttpBuildCacheProvider.ts | 58.26 | 45.55 | 61.11 | 58.26 | 63,108-182,192,218,222-223,270-278,287,326-328,335,348-371,389-390,399-409
|
|
23
|
+
RushHttpBuildCachePlugin.ts | 0 | 100 | 0 | 0 | 7-77
|
|
24
|
+
index.ts | 0 | 100 | 100 | 0 | 1-3
|
|
25
|
+
-----------------------------|---------|----------|---------|---------|----------------------------------------------------------------------------
|
|
26
|
+
-------------------- Finished (1.935s) --------------------
|
|
27
|
+
Project: @rushstack/rush-http-build-cache-plugin@5.97.1
|
|
28
|
+
Heft version: 0.50.5
|
|
28
29
|
Node version: v14.21.3
|
|
29
|
-
This project does not define the caching behavior of the "_phase:test" command, so caching has been disabled.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ITerminal, Executable } from '@rushstack/node-core-library';
|
|
1
|
+
import { ITerminal, Executable, Async } from '@rushstack/node-core-library';
|
|
2
2
|
import {
|
|
3
3
|
ICloudBuildCacheProvider,
|
|
4
4
|
ICredentialCacheEntry,
|
|
@@ -34,6 +34,7 @@ export interface IHttpBuildCacheProviderOptions {
|
|
|
34
34
|
url: string;
|
|
35
35
|
tokenHandler?: IHttpBuildCacheTokenHandler;
|
|
36
36
|
uploadMethod?: string;
|
|
37
|
+
minHttpRetryDelayMs?: number;
|
|
37
38
|
headers?: Record<string, string>;
|
|
38
39
|
cacheKeyPrefix?: string;
|
|
39
40
|
isCacheWriteAllowed: boolean;
|
|
@@ -41,6 +42,9 @@ export interface IHttpBuildCacheProviderOptions {
|
|
|
41
42
|
rushProjectRoot: string;
|
|
42
43
|
}
|
|
43
44
|
|
|
45
|
+
const MAX_HTTP_CACHE_ATTEMPTS: number = 3;
|
|
46
|
+
const DEFAULT_MIN_HTTP_RETRY_DELAY_MS = 2500;
|
|
47
|
+
|
|
44
48
|
export class HttpBuildCacheProvider implements ICloudBuildCacheProvider {
|
|
45
49
|
private readonly _pluginName: string;
|
|
46
50
|
private readonly _rushSession: RushSession;
|
|
@@ -52,6 +56,7 @@ export class HttpBuildCacheProvider implements ICloudBuildCacheProvider {
|
|
|
52
56
|
private readonly _headers: Record<string, string>;
|
|
53
57
|
private readonly _cacheKeyPrefix: string;
|
|
54
58
|
private readonly _tokenHandler: IHttpBuildCacheTokenHandler | undefined;
|
|
59
|
+
private readonly _minHttpRetryDelayMs: number;
|
|
55
60
|
private __credentialCacheId: string | undefined;
|
|
56
61
|
|
|
57
62
|
public get isCacheWriteAllowed(): boolean {
|
|
@@ -70,6 +75,7 @@ export class HttpBuildCacheProvider implements ICloudBuildCacheProvider {
|
|
|
70
75
|
this._headers = options.headers ?? {};
|
|
71
76
|
this._tokenHandler = options.tokenHandler;
|
|
72
77
|
this._cacheKeyPrefix = options.cacheKeyPrefix ?? '';
|
|
78
|
+
this._minHttpRetryDelayMs = options.minHttpRetryDelayMs ?? DEFAULT_MIN_HTTP_RETRY_DELAY_MS;
|
|
73
79
|
}
|
|
74
80
|
|
|
75
81
|
public async tryGetCacheEntryBufferByIdAsync(
|
|
@@ -83,7 +89,8 @@ export class HttpBuildCacheProvider implements ICloudBuildCacheProvider {
|
|
|
83
89
|
method: 'GET',
|
|
84
90
|
body: undefined,
|
|
85
91
|
warningText: 'Could not get cache entry',
|
|
86
|
-
readBody: true
|
|
92
|
+
readBody: true,
|
|
93
|
+
maxAttempts: MAX_HTTP_CACHE_ATTEMPTS
|
|
87
94
|
});
|
|
88
95
|
|
|
89
96
|
return Buffer.isBuffer(result) ? result : undefined;
|
|
@@ -112,7 +119,8 @@ export class HttpBuildCacheProvider implements ICloudBuildCacheProvider {
|
|
|
112
119
|
method: this._uploadMethod,
|
|
113
120
|
body: objectBuffer,
|
|
114
121
|
warningText: 'Could not write cache entry',
|
|
115
|
-
readBody: false
|
|
122
|
+
readBody: false,
|
|
123
|
+
maxAttempts: MAX_HTTP_CACHE_ATTEMPTS
|
|
116
124
|
});
|
|
117
125
|
|
|
118
126
|
return result !== false;
|
|
@@ -197,6 +205,7 @@ export class HttpBuildCacheProvider implements ICloudBuildCacheProvider {
|
|
|
197
205
|
body: BodyInit | undefined;
|
|
198
206
|
warningText: string;
|
|
199
207
|
readBody: boolean;
|
|
208
|
+
maxAttempts: number;
|
|
200
209
|
credentialOptions?: CredentialsOptions;
|
|
201
210
|
}): Promise<Buffer | boolean> {
|
|
202
211
|
const { terminal, relUrl, method, body, warningText, readBody, credentialOptions } = options;
|
|
@@ -227,13 +236,33 @@ export class HttpBuildCacheProvider implements ICloudBuildCacheProvider {
|
|
|
227
236
|
});
|
|
228
237
|
|
|
229
238
|
if (!response.ok) {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
239
|
+
const isNonCredentialResponse = response.status >= 500 && response.status < 600;
|
|
240
|
+
|
|
241
|
+
if (
|
|
242
|
+
!isNonCredentialResponse &&
|
|
243
|
+
typeof credentials !== 'string' &&
|
|
244
|
+
safeCredentialOptions === CredentialsOptions.Optional
|
|
245
|
+
) {
|
|
246
|
+
// If we don't already have credentials yet, and we got a response from the server
|
|
247
|
+
// that is a "normal" failure (4xx), then we assume that credentials are probably
|
|
248
|
+
// required. Re-attempt the request, requiring credentials this time.
|
|
249
|
+
//
|
|
250
|
+
// This counts as part of the "first attempt", so it is not included in the max attempts
|
|
234
251
|
return await this._http({ ...options, credentialOptions: CredentialsOptions.Required });
|
|
235
252
|
}
|
|
236
253
|
|
|
254
|
+
if (options.maxAttempts > 1) {
|
|
255
|
+
// Pause a bit before retrying in case the server is busy
|
|
256
|
+
// Add some random jitter to the retry so we can spread out load on the remote service
|
|
257
|
+
// A proper solution might add exponential back off in case the retry count is high (10 or more)
|
|
258
|
+
const factor = 1.0 + Math.random(); // A random number between 1.0 and 2.0
|
|
259
|
+
const retryDelay = Math.floor(factor * this._minHttpRetryDelayMs);
|
|
260
|
+
|
|
261
|
+
await Async.sleep(retryDelay);
|
|
262
|
+
|
|
263
|
+
return await this._http({ ...options, maxAttempts: options.maxAttempts - 1 });
|
|
264
|
+
}
|
|
265
|
+
|
|
237
266
|
this._reportFailure(terminal, method, response, false, warningText);
|
|
238
267
|
return false;
|
|
239
268
|
}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
2
|
+
// See LICENSE in the project root for license information.
|
|
3
|
+
|
|
2
4
|
import type { IRushPlugin, RushSession, RushConfiguration } from '@rushstack/rush-sdk';
|
|
3
5
|
import type { HttpBuildCacheProvider, IHttpBuildCacheProviderOptions } from './HttpBuildCacheProvider';
|
|
4
6
|
|
|
5
|
-
const HttpBuildCacheProviderModule: typeof import('./HttpBuildCacheProvider') = Import.lazy(
|
|
6
|
-
'./HttpBuildCacheProvider',
|
|
7
|
-
require
|
|
8
|
-
);
|
|
9
|
-
|
|
10
7
|
const PLUGIN_NAME: string = 'HttpBuildCachePlugin';
|
|
11
8
|
|
|
12
9
|
/**
|
|
@@ -56,31 +53,29 @@ export class RushHttpBuildCachePlugin implements IRushPlugin {
|
|
|
56
53
|
|
|
57
54
|
public apply(rushSession: RushSession, rushConfig: RushConfiguration): void {
|
|
58
55
|
rushSession.hooks.initialize.tap(this.pluginName, () => {
|
|
59
|
-
rushSession.registerCloudBuildCacheProviderFactory(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
).httpConfiguration;
|
|
56
|
+
rushSession.registerCloudBuildCacheProviderFactory('http', async (buildCacheConfig) => {
|
|
57
|
+
const config: IRushHttpBuildCachePluginConfig = (
|
|
58
|
+
buildCacheConfig as typeof buildCacheConfig & {
|
|
59
|
+
httpConfiguration: IRushHttpBuildCachePluginConfig;
|
|
60
|
+
}
|
|
61
|
+
).httpConfiguration;
|
|
67
62
|
|
|
68
|
-
|
|
63
|
+
const { url, uploadMethod, headers, tokenHandler, cacheKeyPrefix, isCacheWriteAllowed } = config;
|
|
69
64
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
65
|
+
const options: IHttpBuildCacheProviderOptions = {
|
|
66
|
+
pluginName: this.pluginName,
|
|
67
|
+
rushProjectRoot: rushConfig.rushJsonFolder,
|
|
68
|
+
url: url,
|
|
69
|
+
uploadMethod: uploadMethod,
|
|
70
|
+
headers: headers,
|
|
71
|
+
tokenHandler: tokenHandler,
|
|
72
|
+
cacheKeyPrefix: cacheKeyPrefix,
|
|
73
|
+
isCacheWriteAllowed: !!isCacheWriteAllowed
|
|
74
|
+
};
|
|
80
75
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
);
|
|
76
|
+
const { HttpBuildCacheProvider } = await import('./HttpBuildCacheProvider');
|
|
77
|
+
return new HttpBuildCacheProvider(options, rushSession);
|
|
78
|
+
});
|
|
84
79
|
});
|
|
85
80
|
}
|
|
86
81
|
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
2
|
+
// See LICENSE in the project root for license information.
|
|
3
|
+
|
|
4
|
+
jest.mock('node-fetch', function () {
|
|
5
|
+
return Object.assign(jest.fn(), jest.requireActual('node-fetch'));
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
import fetch, { Response } from 'node-fetch';
|
|
9
|
+
import { RushSession, EnvironmentConfiguration } from '@rushstack/rush-sdk';
|
|
10
|
+
import { StringBufferTerminalProvider, Terminal } from '@rushstack/node-core-library';
|
|
11
|
+
|
|
12
|
+
import { HttpBuildCacheProvider } from '../HttpBuildCacheProvider';
|
|
13
|
+
|
|
14
|
+
const EXAMPLE_OPTIONS = {
|
|
15
|
+
url: 'https://buildcache.example.acme.com',
|
|
16
|
+
tokenHandler: {
|
|
17
|
+
exec: 'node',
|
|
18
|
+
args: ['tokenHandler.js']
|
|
19
|
+
},
|
|
20
|
+
uploadMethod: 'POST',
|
|
21
|
+
isCacheWriteAllowed: false,
|
|
22
|
+
pluginName: 'example-plugin',
|
|
23
|
+
rushProjectRoot: '/repo',
|
|
24
|
+
minHttpRetryDelayMs: 1
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
describe('HttpBuildCacheProvider', () => {
|
|
28
|
+
let terminalBuffer: StringBufferTerminalProvider;
|
|
29
|
+
let terminal!: Terminal;
|
|
30
|
+
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
terminalBuffer = new StringBufferTerminalProvider();
|
|
33
|
+
terminal = new Terminal(terminalBuffer);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe('tryGetCacheEntryBufferByIdAsync', () => {
|
|
37
|
+
it('prints warning if read credentials are not available', async () => {
|
|
38
|
+
jest.spyOn(EnvironmentConfiguration, 'buildCacheCredential', 'get').mockReturnValue(undefined);
|
|
39
|
+
|
|
40
|
+
const session: RushSession = {} as RushSession;
|
|
41
|
+
const provider = new HttpBuildCacheProvider(EXAMPLE_OPTIONS, session);
|
|
42
|
+
|
|
43
|
+
mocked(fetch).mockResolvedValue(
|
|
44
|
+
new Response('Unauthorized', {
|
|
45
|
+
status: 401,
|
|
46
|
+
statusText: 'Unauthorized'
|
|
47
|
+
})
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const result = await provider.tryGetCacheEntryBufferByIdAsync(terminal, 'some-key');
|
|
51
|
+
expect(result).toBe(undefined);
|
|
52
|
+
expect(fetch).toHaveBeenCalledTimes(1);
|
|
53
|
+
expect(fetch).toHaveBeenNthCalledWith(1, 'https://buildcache.example.acme.com/some-key', {
|
|
54
|
+
body: undefined,
|
|
55
|
+
headers: {},
|
|
56
|
+
method: 'GET',
|
|
57
|
+
redirect: 'follow'
|
|
58
|
+
});
|
|
59
|
+
expect(terminalBuffer.getWarningOutput()).toMatchInlineSnapshot(
|
|
60
|
+
`"Error getting cache entry: Error: Credentials for https://buildcache.example.acme.com/ have not been provided.[n]In CI, verify that RUSH_BUILD_CACHE_CREDENTIAL contains a valid Authorization header value.[n][n]For local developers, run:[n][n] rush update-cloud-credentials --interactive[n][n]"`
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('attempts up to 3 times to download a cache entry', async () => {
|
|
65
|
+
jest.spyOn(EnvironmentConfiguration, 'buildCacheCredential', 'get').mockReturnValue(undefined);
|
|
66
|
+
|
|
67
|
+
const session: RushSession = {} as RushSession;
|
|
68
|
+
const provider = new HttpBuildCacheProvider(EXAMPLE_OPTIONS, session);
|
|
69
|
+
|
|
70
|
+
mocked(fetch).mockResolvedValueOnce(
|
|
71
|
+
new Response('InternalServiceError', {
|
|
72
|
+
status: 500,
|
|
73
|
+
statusText: 'InternalServiceError'
|
|
74
|
+
})
|
|
75
|
+
);
|
|
76
|
+
mocked(fetch).mockResolvedValueOnce(
|
|
77
|
+
new Response('ServiceUnavailable', {
|
|
78
|
+
status: 503,
|
|
79
|
+
statusText: 'ServiceUnavailable'
|
|
80
|
+
})
|
|
81
|
+
);
|
|
82
|
+
mocked(fetch).mockResolvedValueOnce(
|
|
83
|
+
new Response('BadGateway', {
|
|
84
|
+
status: 504,
|
|
85
|
+
statusText: 'BadGateway'
|
|
86
|
+
})
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const result = await provider.tryGetCacheEntryBufferByIdAsync(terminal, 'some-key');
|
|
90
|
+
expect(result).toBe(undefined);
|
|
91
|
+
expect(fetch).toHaveBeenCalledTimes(3);
|
|
92
|
+
expect(fetch).toHaveBeenNthCalledWith(1, 'https://buildcache.example.acme.com/some-key', {
|
|
93
|
+
body: undefined,
|
|
94
|
+
headers: {},
|
|
95
|
+
method: 'GET',
|
|
96
|
+
redirect: 'follow'
|
|
97
|
+
});
|
|
98
|
+
expect(fetch).toHaveBeenNthCalledWith(2, 'https://buildcache.example.acme.com/some-key', {
|
|
99
|
+
body: undefined,
|
|
100
|
+
headers: {},
|
|
101
|
+
method: 'GET',
|
|
102
|
+
redirect: 'follow'
|
|
103
|
+
});
|
|
104
|
+
expect(fetch).toHaveBeenNthCalledWith(3, 'https://buildcache.example.acme.com/some-key', {
|
|
105
|
+
body: undefined,
|
|
106
|
+
headers: {},
|
|
107
|
+
method: 'GET',
|
|
108
|
+
redirect: 'follow'
|
|
109
|
+
});
|
|
110
|
+
expect(terminalBuffer.getWarningOutput()).toMatchInlineSnapshot(
|
|
111
|
+
`"Could not get cache entry: HTTP 504: BadGateway[n]"`
|
|
112
|
+
);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|