From 78fc2f289664950a6cacaef2e0308781ea15059c Mon Sep 17 00:00:00 2001 From: Max Gale Date: Thu, 24 Sep 2026 10:54:49 -0400 Subject: [PATCH] cache: propagate github instance slug --- packages/cache/__tests__/instanceSlug.test.ts | 50 +++++++++++++++++++ .../cache/src/internal/cacheHttpClient.ts | 8 ++- 2 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 packages/cache/__tests__/instanceSlug.test.ts diff --git a/packages/cache/__tests__/instanceSlug.test.ts b/packages/cache/__tests__/instanceSlug.test.ts new file mode 100644 index 0000000000..9b1c35fe5e --- /dev/null +++ b/packages/cache/__tests__/instanceSlug.test.ts @@ -0,0 +1,50 @@ +import * as http from 'http' +import {AddressInfo} from 'net' +import fetch from 'node-fetch' +import {getCacheEntry, reserveCache} from '../src/internal/cacheHttpClient' + +jest.mock('node-fetch', () => jest.fn()) +jest.mock('../src/internal/downloadUtils', () => ({})) + +test.each([undefined, 'enterprise'])( + 'sends instance slug on reserve and restore (%s)', + async slug => { + const previous = {...process.env} + let receivedSlug: string | string[] | undefined + const server = http.createServer((req, res) => { + receivedSlug = req.headers['x-blacksmith-instance-slug'] + req.resume() + res.writeHead(200, {'Content-Type': 'application/json'}) + res.end(JSON.stringify({cacheId: 1})) + }) + await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)) + try { + if (slug) process.env.BLACKSMITH_INSTANCE_SLUG = slug + else delete process.env.BLACKSMITH_INSTANCE_SLUG + process.env.BLACKSMITH_CACHE_URL = `http://127.0.0.1:${ + (server.address() as AddressInfo).port + }` + process.env.GITHUB_REPO_NAME = 'owner/repo' + process.env.BLACKSMITH_CACHE_TOKEN = 'test-token' + await reserveCache('key', ['node_modules']) + expect(receivedSlug).toBe(slug || 'github') + ;(fetch as jest.MockedFunction).mockResolvedValue({ + status: 204 + } as any) + await getCacheEntry(['key'], ['node_modules']) + expect(fetch).toHaveBeenCalledWith( + expect.any(String), + expect.objectContaining({ + headers: expect.objectContaining({ + 'X-Blacksmith-Instance-Slug': slug || 'github' + }) + }) + ) + } finally { + process.env = previous + await new Promise((resolve, reject) => + server.close(err => (err ? reject(err) : resolve())) + ) + } + } +) diff --git a/packages/cache/src/internal/cacheHttpClient.ts b/packages/cache/src/internal/cacheHttpClient.ts index 40a90b7ca8..665ba89bf3 100644 --- a/packages/cache/src/internal/cacheHttpClient.ts +++ b/packages/cache/src/internal/cacheHttpClient.ts @@ -64,6 +64,8 @@ function getRequestOptions(): RequestOptions { const requestOptions: RequestOptions = { headers: { Accept: createAcceptHeader('application/json', '6.0-preview.1'), + 'X-Blacksmith-Instance-Slug': + process.env['BLACKSMITH_INSTANCE_SLUG'] || 'github', 'X-Github-Repo-Name': process.env['GITHUB_REPO_NAME'] } } @@ -141,6 +143,8 @@ export async function getCacheEntry( headers: { Accept: createAcceptHeader('application/json', '6.0-preview.1'), 'X-Github-Repo-Name': repoName || '', + 'X-Blacksmith-Instance-Slug': + process.env['BLACKSMITH_INSTANCE_SLUG'] || 'github', Authorization: `Bearer ${cacheToken}`, 'X-Cache-Region': process.env['BLACKSMITH_REGION'] ?? 'eu-central', 'User-Agent': 'node-fetch/cache' @@ -182,7 +186,7 @@ export async function getCacheEntry( } catch (error) { const isTimeout = error.name === 'AbortError' const status = error.response?.status - + if ((status && status >= 500) || isTimeout) { retries++ if (retries <= maxRetries) { @@ -198,7 +202,7 @@ export async function getCacheEntry( continue } } - + if (status) { throw new Error(`Cache service responded with ${status}`) } else if (isTimeout) {