feat: expand the configuration options for release manifests
Ultimately, this paves the way for more configuration options with cli bump command when working in environments that are closed / air-gapped from the public internet. Signed-off-by: Tim Klever <tim.v.klever@aexp.com>
This commit is contained in:
@@ -86,6 +86,71 @@ describe('Release Manifests', () => {
|
||||
getManifestByVersion({ version: '0.0.0', fetch: mockFetch }),
|
||||
).rejects.toThrow('No release found for 0.0.0 version');
|
||||
});
|
||||
|
||||
it('should allow overriding the versions host', async () => {
|
||||
const mockFetch = jest.fn().mockImplementation(async url => ({
|
||||
status: 200,
|
||||
url,
|
||||
json: () => ({
|
||||
packages: [{ name: '@backstage/core', version: '2.3.4' }],
|
||||
}),
|
||||
}));
|
||||
|
||||
const pkgs = await getManifestByVersion({
|
||||
version: '0.0.0',
|
||||
fetch: mockFetch,
|
||||
versionsBaseUrl: 'https://versions.some-test-host.com',
|
||||
});
|
||||
|
||||
expect(pkgs.packages).toEqual([
|
||||
{
|
||||
name: '@backstage/core',
|
||||
version: '2.3.4',
|
||||
},
|
||||
]);
|
||||
|
||||
expect(mockFetch).toHaveBeenCalledWith(
|
||||
'https://versions.some-test-host.com/v1/releases/0.0.0/manifest.json',
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
|
||||
it('should allow overriding github host', async () => {
|
||||
const mockFetch = jest.fn().mockImplementation(async url => {
|
||||
if (
|
||||
url ===
|
||||
'https://versions.some-test-host.com/v1/releases/0.0.0/manifest.json'
|
||||
) {
|
||||
return {
|
||||
status: 200,
|
||||
url,
|
||||
json: () => ({
|
||||
packages: [{ name: '@backstage/core', version: '2.3.4' }],
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error('Host not found');
|
||||
});
|
||||
|
||||
const pkgs = await getManifestByVersion({
|
||||
version: '0.0.0',
|
||||
fetch: mockFetch,
|
||||
gitHubRawBaseUrl: 'https://versions.some-test-host.com',
|
||||
});
|
||||
|
||||
expect(pkgs.packages).toEqual([
|
||||
{
|
||||
name: '@backstage/core',
|
||||
version: '2.3.4',
|
||||
},
|
||||
]);
|
||||
|
||||
expect(mockFetch).toHaveBeenCalledWith(
|
||||
'https://versions.some-test-host.com/v1/releases/0.0.0/manifest.json',
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getManifestByReleaseLine', () => {
|
||||
@@ -119,6 +184,121 @@ describe('Release Manifests', () => {
|
||||
getManifestByReleaseLine({ releaseLine: 'foo' }),
|
||||
).rejects.toThrow("No 'foo' release line found");
|
||||
});
|
||||
|
||||
it('should allow overriding the fetch implementation', async () => {
|
||||
const mockFetch = jest.fn().mockImplementation(async url => ({
|
||||
status: 200,
|
||||
url,
|
||||
json: () => ({
|
||||
packages: [{ name: '@backstage/core', version: '1.2.3' }],
|
||||
}),
|
||||
}));
|
||||
|
||||
const pkgs = await getManifestByReleaseLine({
|
||||
releaseLine: 'main',
|
||||
fetch: mockFetch,
|
||||
});
|
||||
|
||||
expect(pkgs.packages).toEqual([
|
||||
{
|
||||
name: '@backstage/core',
|
||||
version: '1.2.3',
|
||||
},
|
||||
]);
|
||||
|
||||
mockFetch.mockImplementation(async url => ({
|
||||
status: 404,
|
||||
url,
|
||||
}));
|
||||
|
||||
await expect(
|
||||
getManifestByReleaseLine({ releaseLine: 'foo', fetch: mockFetch }),
|
||||
).rejects.toThrow("No 'foo' release line found");
|
||||
});
|
||||
|
||||
it('should allow overriding the versions host', async () => {
|
||||
const mockFetch = jest.fn().mockImplementation(async url => ({
|
||||
status: 200,
|
||||
url,
|
||||
json: () => ({
|
||||
packages: [{ name: '@backstage/core', version: '1.2.3' }],
|
||||
}),
|
||||
}));
|
||||
|
||||
const pkgs = await getManifestByReleaseLine({
|
||||
releaseLine: 'main',
|
||||
fetch: mockFetch,
|
||||
versionsBaseUrl: 'https://versions.some-test-host.com',
|
||||
});
|
||||
|
||||
expect(pkgs.packages).toEqual([
|
||||
{
|
||||
name: '@backstage/core',
|
||||
version: '1.2.3',
|
||||
},
|
||||
]);
|
||||
|
||||
expect(mockFetch).toHaveBeenCalledWith(
|
||||
'https://versions.some-test-host.com/v1/tags/main/manifest.json',
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
|
||||
it('should allow overriding github host', async () => {
|
||||
const mockFetch = jest.fn().mockImplementation(async url => {
|
||||
if (
|
||||
url ===
|
||||
'https://hosted.raw.internal-github.com/backstage/versions/main/v1/tags/main'
|
||||
) {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
url,
|
||||
text: () =>
|
||||
'https://hosted.raw.internal-github.com/backstage/versions/tags/main',
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
url ===
|
||||
'https://hosted.raw.internal-github.com/backstage/versions/tags/main/manifest.json'
|
||||
) {
|
||||
return {
|
||||
status: 200,
|
||||
url,
|
||||
json: () => ({
|
||||
packages: [{ name: '@backstage/core', version: '1.2.3' }],
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error('Host Not Found');
|
||||
});
|
||||
|
||||
const pkgs = await getManifestByReleaseLine({
|
||||
releaseLine: 'main',
|
||||
fetch: mockFetch,
|
||||
gitHubRawBaseUrl:
|
||||
'https://hosted.raw.internal-github.com/backstage/versions/main',
|
||||
});
|
||||
|
||||
expect(pkgs.packages).toEqual([
|
||||
{
|
||||
name: '@backstage/core',
|
||||
version: '1.2.3',
|
||||
},
|
||||
]);
|
||||
|
||||
expect(mockFetch).toHaveBeenCalledWith(
|
||||
'https://hosted.raw.internal-github.com/backstage/versions/main/v1/tags/main',
|
||||
expect.anything(),
|
||||
);
|
||||
|
||||
expect(mockFetch).toHaveBeenCalledWith(
|
||||
'https://hosted.raw.internal-github.com/backstage/versions/tags/main/manifest.json',
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@ export type GetManifestByVersionOptions = {
|
||||
url: string,
|
||||
options?: { signal?: AbortSignal },
|
||||
) => Promise<Pick<Response, 'status' | 'json' | 'url'>>;
|
||||
gitHubRawBaseUrl?: string;
|
||||
versionsBaseUrl?: string;
|
||||
};
|
||||
|
||||
// Wait for waitMs, or until signal is aborted.
|
||||
@@ -88,19 +90,18 @@ export async function getManifestByVersion(
|
||||
const versionEnc = encodeURIComponent(options.version);
|
||||
|
||||
const fetchFn = options.fetch ?? fetch;
|
||||
const versionsHost = options.versionsBaseUrl ?? VERSIONS_BASE_URL;
|
||||
const gitHubRawBaseUrl = options.gitHubRawBaseUrl ?? GITHUB_RAW_BASE_URL;
|
||||
|
||||
const res = await withFallback(
|
||||
signal =>
|
||||
fetchFn(`${VERSIONS_BASE_URL}/v1/releases/${versionEnc}/manifest.json`, {
|
||||
fetchFn(`${versionsHost}/v1/releases/${versionEnc}/manifest.json`, {
|
||||
signal,
|
||||
}),
|
||||
signal =>
|
||||
fetchFn(
|
||||
`${GITHUB_RAW_BASE_URL}/v1/releases/${versionEnc}/manifest.json`,
|
||||
{
|
||||
signal,
|
||||
},
|
||||
),
|
||||
fetchFn(`${gitHubRawBaseUrl}/v1/releases/${versionEnc}/manifest.json`, {
|
||||
signal,
|
||||
}),
|
||||
500,
|
||||
);
|
||||
if (res.status === 404) {
|
||||
@@ -120,6 +121,12 @@ export async function getManifestByVersion(
|
||||
*/
|
||||
export type GetManifestByReleaseLineOptions = {
|
||||
releaseLine: string;
|
||||
fetch?: (
|
||||
url: string,
|
||||
options?: { signal?: AbortSignal },
|
||||
) => Promise<Pick<Response, 'ok' | 'status' | 'text' | 'json' | 'url'>>;
|
||||
gitHubRawBaseUrl?: string;
|
||||
versionsBaseUrl?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -130,20 +137,27 @@ export async function getManifestByReleaseLine(
|
||||
options: GetManifestByReleaseLineOptions,
|
||||
): Promise<ReleaseManifest> {
|
||||
const releaseEnc = encodeURIComponent(options.releaseLine);
|
||||
|
||||
const fetchFn = options.fetch ?? fetch;
|
||||
const versionsHost = options.versionsBaseUrl ?? VERSIONS_BASE_URL;
|
||||
const gitHubRawBaseUrl = options.gitHubRawBaseUrl ?? GITHUB_RAW_BASE_URL;
|
||||
|
||||
const res = await withFallback(
|
||||
signal =>
|
||||
fetch(`${VERSIONS_BASE_URL}/v1/tags/${releaseEnc}/manifest.json`, {
|
||||
fetchFn(`${versionsHost}/v1/tags/${releaseEnc}/manifest.json`, {
|
||||
signal,
|
||||
}),
|
||||
async signal => {
|
||||
// The release tags are symlinks, which we need to follow manually when fetching from GitHub.
|
||||
const baseUrl = `${GITHUB_RAW_BASE_URL}/v1/tags/${releaseEnc}`;
|
||||
const linkRes = await fetch(baseUrl, { signal });
|
||||
const baseUrl = `${gitHubRawBaseUrl}/v1/tags/${releaseEnc}`;
|
||||
const linkRes = await fetchFn(baseUrl, { signal });
|
||||
if (!linkRes.ok) {
|
||||
return linkRes;
|
||||
}
|
||||
const link = (await linkRes.text()).trim();
|
||||
return fetch(new URL(`${link}/manifest.json`, baseUrl), { signal });
|
||||
return fetchFn(new URL(`${link}/manifest.json`, baseUrl).toString(), {
|
||||
signal,
|
||||
});
|
||||
},
|
||||
1000,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user