mirror of
https://github.com/LukeHagar/redocly-cli.git
synced 2025-12-06 04:21:09 +00:00
feat: report endpoint sunset (#1677)
This commit is contained in:
5
.changeset/tiny-boats-check.md
Normal file
5
.changeset/tiny-boats-check.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@redocly/cli": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Added a warning message to the `push` and `push-status` commands to notify users about upcoming or ongoing resource deprecation.
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
import fetch, { Response } from 'node-fetch';
|
import fetch, { Response } from 'node-fetch';
|
||||||
import * as FormData from 'form-data';
|
import * as FormData from 'form-data';
|
||||||
|
import { red, yellow } from 'colorette';
|
||||||
|
|
||||||
import { ReuniteApiClient, PushPayload, ReuniteApiError } from '../api-client';
|
import { ReuniteApi, PushPayload, ReuniteApiError } from '../api-client';
|
||||||
|
|
||||||
jest.mock('node-fetch', () => ({
|
jest.mock('node-fetch', () => ({
|
||||||
default: jest.fn(),
|
default: jest.fn(),
|
||||||
@@ -21,10 +22,10 @@ describe('ApiClient', () => {
|
|||||||
const expectedUserAgent = `redocly-cli/${version} ${command}`;
|
const expectedUserAgent = `redocly-cli/${version} ${command}`;
|
||||||
|
|
||||||
describe('getDefaultBranch()', () => {
|
describe('getDefaultBranch()', () => {
|
||||||
let apiClient: ReuniteApiClient;
|
let apiClient: ReuniteApi;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
apiClient = new ReuniteApiClient({ domain: testDomain, apiKey: testToken, version, command });
|
apiClient = new ReuniteApi({ domain: testDomain, apiKey: testToken, version, command });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get default project branch', async () => {
|
it('should get default project branch', async () => {
|
||||||
@@ -90,22 +91,23 @@ describe('ApiClient', () => {
|
|||||||
mountBranchName: 'remote-mount-branch-name',
|
mountBranchName: 'remote-mount-branch-name',
|
||||||
mountPath: 'remote-mount-path',
|
mountPath: 'remote-mount-path',
|
||||||
};
|
};
|
||||||
let apiClient: ReuniteApiClient;
|
|
||||||
|
const responseMock = {
|
||||||
|
id: 'remote-id',
|
||||||
|
type: 'CICD',
|
||||||
|
mountPath: 'remote-mount-path',
|
||||||
|
mountBranchName: 'remote-mount-branch-name',
|
||||||
|
organizationId: testOrg,
|
||||||
|
projectId: testProject,
|
||||||
|
};
|
||||||
|
|
||||||
|
let apiClient: ReuniteApi;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
apiClient = new ReuniteApiClient({ domain: testDomain, apiKey: testToken, version, command });
|
apiClient = new ReuniteApi({ domain: testDomain, apiKey: testToken, version, command });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should upsert remote', async () => {
|
it('should upsert remote', async () => {
|
||||||
const responseMock = {
|
|
||||||
id: 'remote-id',
|
|
||||||
type: 'CICD',
|
|
||||||
mountPath: 'remote-mount-path',
|
|
||||||
mountBranchName: 'remote-mount-branch-name',
|
|
||||||
organizationId: testOrg,
|
|
||||||
projectId: testProject,
|
|
||||||
};
|
|
||||||
|
|
||||||
mockFetchResponse({
|
mockFetchResponse({
|
||||||
ok: true,
|
ok: true,
|
||||||
json: jest.fn().mockResolvedValue(responseMock),
|
json: jest.fn().mockResolvedValue(responseMock),
|
||||||
@@ -204,10 +206,10 @@ describe('ApiClient', () => {
|
|||||||
outdated: false,
|
outdated: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let apiClient: ReuniteApiClient;
|
let apiClient: ReuniteApi;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
apiClient = new ReuniteApiClient({ domain: testDomain, apiKey: testToken, version, command });
|
apiClient = new ReuniteApi({ domain: testDomain, apiKey: testToken, version, command });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should push to remote', async () => {
|
it('should push to remote', async () => {
|
||||||
@@ -284,4 +286,165 @@ describe('ApiClient', () => {
|
|||||||
).rejects.toThrow(new ReuniteApiError('Failed to push. Not found.', 404));
|
).rejects.toThrow(new ReuniteApiError('Failed to push. Not found.', 404));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Sunset header', () => {
|
||||||
|
const upsertRemoteMock = {
|
||||||
|
requestFn: () =>
|
||||||
|
apiClient.remotes.upsert(testOrg, testProject, {
|
||||||
|
mountBranchName: 'remote-mount-branch-name',
|
||||||
|
mountPath: 'remote-mount-path',
|
||||||
|
}),
|
||||||
|
responseBody: {
|
||||||
|
id: 'remote-id',
|
||||||
|
type: 'CICD',
|
||||||
|
mountPath: 'remote-mount-path',
|
||||||
|
mountBranchName: 'remote-mount-branch-name',
|
||||||
|
organizationId: testOrg,
|
||||||
|
projectId: testProject,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDefaultBranchMock = {
|
||||||
|
requestFn: () => apiClient.remotes.getDefaultBranch(testOrg, testProject),
|
||||||
|
responseBody: {
|
||||||
|
branchName: 'test-branch',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const pushMock = {
|
||||||
|
requestFn: () =>
|
||||||
|
apiClient.remotes.push(
|
||||||
|
testOrg,
|
||||||
|
testProject,
|
||||||
|
{
|
||||||
|
remoteId: 'test-remote-id',
|
||||||
|
commit: {
|
||||||
|
message: 'test-message',
|
||||||
|
author: {
|
||||||
|
name: 'test-name',
|
||||||
|
email: 'test-email',
|
||||||
|
},
|
||||||
|
branchName: 'test-branch-name',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[{ path: 'some-file.yaml', stream: Buffer.from('text content') }]
|
||||||
|
),
|
||||||
|
responseBody: {
|
||||||
|
branchName: 'rem/cicd/rem_01he7sr6ys2agb7w0g9t7978fn-main',
|
||||||
|
hasChanges: true,
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
type: 'file',
|
||||||
|
name: 'some-file.yaml',
|
||||||
|
path: 'docs/remotes/some-file.yaml',
|
||||||
|
lastModified: 1698925132394.2993,
|
||||||
|
mimeType: 'text/yaml',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
commitSha: 'bb23a2f8e012ac0b7b9961b57fb40d8686b21b43',
|
||||||
|
outdated: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const endpointMocks = [upsertRemoteMock, getDefaultBranchMock, pushMock];
|
||||||
|
|
||||||
|
let apiClient: ReuniteApi;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
apiClient = new ReuniteApi({ domain: testDomain, apiKey: testToken, version, command });
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each(endpointMocks)(
|
||||||
|
'should report endpoint sunset in the past',
|
||||||
|
async ({ responseBody, requestFn }) => {
|
||||||
|
jest.spyOn(process.stdout, 'write').mockImplementationOnce(() => true);
|
||||||
|
const sunsetDate = new Date('2024-09-06T12:30:32.456Z');
|
||||||
|
|
||||||
|
mockFetchResponse({
|
||||||
|
ok: true,
|
||||||
|
json: jest.fn().mockResolvedValue(responseBody),
|
||||||
|
headers: new Headers({
|
||||||
|
Sunset: sunsetDate.toISOString(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
await requestFn();
|
||||||
|
apiClient.reportSunsetWarnings();
|
||||||
|
|
||||||
|
expect(process.stdout.write).toHaveBeenCalledWith(
|
||||||
|
red(
|
||||||
|
`The "push" command is not compatible with your version of Redocly CLI. Update to the latest version by running "npm install @redocly/cli@latest".\n\n`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it.each(endpointMocks)(
|
||||||
|
'should report endpoint sunset in the future',
|
||||||
|
async ({ responseBody, requestFn }) => {
|
||||||
|
jest.spyOn(process.stdout, 'write').mockImplementationOnce(() => true);
|
||||||
|
const sunsetDate = new Date(Date.now() + 1000 * 60 * 60 * 24);
|
||||||
|
|
||||||
|
mockFetchResponse({
|
||||||
|
ok: true,
|
||||||
|
json: jest.fn().mockResolvedValue(responseBody),
|
||||||
|
headers: new Headers({
|
||||||
|
Sunset: sunsetDate.toISOString(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
await requestFn();
|
||||||
|
apiClient.reportSunsetWarnings();
|
||||||
|
|
||||||
|
expect(process.stdout.write).toHaveBeenCalledWith(
|
||||||
|
yellow(
|
||||||
|
`The "push" command will be incompatible with your version of Redocly CLI after ${sunsetDate.toLocaleString()}. Update to the latest version by running "npm install @redocly/cli@latest".\n\n`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it('should report only expired resource', async () => {
|
||||||
|
jest.spyOn(process.stdout, 'write').mockImplementationOnce(() => true);
|
||||||
|
|
||||||
|
mockFetchResponse({
|
||||||
|
ok: true,
|
||||||
|
json: jest.fn().mockResolvedValue(upsertRemoteMock.responseBody),
|
||||||
|
headers: new Headers({
|
||||||
|
Sunset: new Date('2024-08-06T12:30:32.456Z').toISOString(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
await upsertRemoteMock.requestFn();
|
||||||
|
|
||||||
|
mockFetchResponse({
|
||||||
|
ok: true,
|
||||||
|
json: jest.fn().mockResolvedValue(getDefaultBranchMock.responseBody),
|
||||||
|
headers: new Headers({
|
||||||
|
Sunset: new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
await getDefaultBranchMock.requestFn();
|
||||||
|
|
||||||
|
mockFetchResponse({
|
||||||
|
ok: true,
|
||||||
|
json: jest.fn().mockResolvedValue(pushMock.responseBody),
|
||||||
|
headers: new Headers({
|
||||||
|
Sunset: new Date('2024-08-06T12:30:32.456Z').toISOString(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
await pushMock.requestFn();
|
||||||
|
|
||||||
|
apiClient.reportSunsetWarnings();
|
||||||
|
|
||||||
|
expect(process.stdout.write).toHaveBeenCalledTimes(1);
|
||||||
|
expect(process.stdout.write).toHaveBeenCalledWith(
|
||||||
|
red(
|
||||||
|
`The "push" command is not compatible with your version of Redocly CLI. Update to the latest version by running "npm install @redocly/cli@latest".\n\n`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { yellow, red } from 'colorette';
|
||||||
import * as FormData from 'form-data';
|
import * as FormData from 'form-data';
|
||||||
import fetchWithTimeout, {
|
import fetchWithTimeout, {
|
||||||
type FetchWithTimeoutOptions,
|
type FetchWithTimeoutOptions,
|
||||||
@@ -13,15 +14,84 @@ import type {
|
|||||||
UpsertRemoteResponse,
|
UpsertRemoteResponse,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
|
interface BaseApiClient {
|
||||||
|
request(url: string, options: FetchWithTimeoutOptions): Promise<Response>;
|
||||||
|
}
|
||||||
|
type CommandOption = 'push' | 'push-status';
|
||||||
|
export type SunsetWarning = { sunsetDate: Date; isSunsetExpired: boolean };
|
||||||
|
export type SunsetWarningsBuffer = SunsetWarning[];
|
||||||
|
|
||||||
export class ReuniteApiError extends Error {
|
export class ReuniteApiError extends Error {
|
||||||
constructor(message: string, public status: number) {
|
constructor(message: string, public status: number) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReuniteBaseApiClient {
|
class ReuniteApiClient implements BaseApiClient {
|
||||||
|
public sunsetWarnings: SunsetWarningsBuffer = [];
|
||||||
|
|
||||||
constructor(protected version: string, protected command: string) {}
|
constructor(protected version: string, protected command: string) {}
|
||||||
|
|
||||||
|
public async request(url: string, options: FetchWithTimeoutOptions) {
|
||||||
|
const headers = {
|
||||||
|
...options.headers,
|
||||||
|
'user-agent': `redocly-cli/${this.version.trim()} ${this.command}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await fetchWithTimeout(url, {
|
||||||
|
...options,
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.collectSunsetWarning(response);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private collectSunsetWarning(response: Response) {
|
||||||
|
const sunsetTime = this.getSunsetDate(response);
|
||||||
|
|
||||||
|
if (!sunsetTime) return;
|
||||||
|
|
||||||
|
const sunsetDate = new Date(sunsetTime);
|
||||||
|
|
||||||
|
if (sunsetTime > Date.now()) {
|
||||||
|
this.sunsetWarnings.push({
|
||||||
|
sunsetDate,
|
||||||
|
isSunsetExpired: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.sunsetWarnings.push({
|
||||||
|
sunsetDate,
|
||||||
|
isSunsetExpired: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSunsetDate(response: Response): number | undefined {
|
||||||
|
const { headers } = response;
|
||||||
|
|
||||||
|
if (!headers) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sunsetDate = headers.get('sunset') || headers.get('Sunset');
|
||||||
|
|
||||||
|
if (!sunsetDate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Date.parse(sunsetDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RemotesApi {
|
||||||
|
constructor(
|
||||||
|
private client: BaseApiClient,
|
||||||
|
private readonly domain: string,
|
||||||
|
private readonly apiKey: string
|
||||||
|
) {}
|
||||||
|
|
||||||
protected async getParsedResponse<T>(response: Response): Promise<T> {
|
protected async getParsedResponse<T>(response: Response): Promise<T> {
|
||||||
const responseBody = await response.json();
|
const responseBody = await response.json();
|
||||||
|
|
||||||
@@ -35,32 +105,9 @@ class ReuniteBaseApiClient {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected request(url: string, options: FetchWithTimeoutOptions) {
|
|
||||||
const headers = {
|
|
||||||
...options.headers,
|
|
||||||
'user-agent': `redocly-cli/${this.version.trim()} ${this.command}`,
|
|
||||||
};
|
|
||||||
|
|
||||||
return fetchWithTimeout(url, {
|
|
||||||
...options,
|
|
||||||
headers,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RemotesApiClient extends ReuniteBaseApiClient {
|
|
||||||
constructor(
|
|
||||||
private readonly domain: string,
|
|
||||||
private readonly apiKey: string,
|
|
||||||
version: string,
|
|
||||||
command: string
|
|
||||||
) {
|
|
||||||
super(version, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getDefaultBranch(organizationId: string, projectId: string) {
|
async getDefaultBranch(organizationId: string, projectId: string) {
|
||||||
try {
|
try {
|
||||||
const response = await this.request(
|
const response = await this.client.request(
|
||||||
`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/source`,
|
`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/source`,
|
||||||
{
|
{
|
||||||
timeout: DEFAULT_FETCH_TIMEOUT,
|
timeout: DEFAULT_FETCH_TIMEOUT,
|
||||||
@@ -95,7 +142,7 @@ class RemotesApiClient extends ReuniteBaseApiClient {
|
|||||||
}
|
}
|
||||||
): Promise<UpsertRemoteResponse> {
|
): Promise<UpsertRemoteResponse> {
|
||||||
try {
|
try {
|
||||||
const response = await this.request(
|
const response = await this.client.request(
|
||||||
`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/remotes`,
|
`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/remotes`,
|
||||||
{
|
{
|
||||||
timeout: DEFAULT_FETCH_TIMEOUT,
|
timeout: DEFAULT_FETCH_TIMEOUT,
|
||||||
@@ -150,7 +197,7 @@ class RemotesApiClient extends ReuniteBaseApiClient {
|
|||||||
|
|
||||||
payload.isMainBranch && formData.append('isMainBranch', 'true');
|
payload.isMainBranch && formData.append('isMainBranch', 'true');
|
||||||
try {
|
try {
|
||||||
const response = await this.request(
|
const response = await this.client.request(
|
||||||
`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/pushes`,
|
`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/pushes`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -183,7 +230,7 @@ class RemotesApiClient extends ReuniteBaseApiClient {
|
|||||||
mountPath: string;
|
mountPath: string;
|
||||||
}) {
|
}) {
|
||||||
try {
|
try {
|
||||||
const response = await this.request(
|
const response = await this.client.request(
|
||||||
`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/remotes?filter=mountPath:/${mountPath}/`,
|
`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/remotes?filter=mountPath:/${mountPath}/`,
|
||||||
{
|
{
|
||||||
timeout: DEFAULT_FETCH_TIMEOUT,
|
timeout: DEFAULT_FETCH_TIMEOUT,
|
||||||
@@ -217,7 +264,7 @@ class RemotesApiClient extends ReuniteBaseApiClient {
|
|||||||
pushId: string;
|
pushId: string;
|
||||||
}) {
|
}) {
|
||||||
try {
|
try {
|
||||||
const response = await this.request(
|
const response = await this.client.request(
|
||||||
`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/pushes/${pushId}`,
|
`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/pushes/${pushId}`,
|
||||||
{
|
{
|
||||||
timeout: DEFAULT_FETCH_TIMEOUT,
|
timeout: DEFAULT_FETCH_TIMEOUT,
|
||||||
@@ -242,8 +289,12 @@ class RemotesApiClient extends ReuniteBaseApiClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ReuniteApiClient {
|
export class ReuniteApi {
|
||||||
remotes: RemotesApiClient;
|
private apiClient: ReuniteApiClient;
|
||||||
|
private version: string;
|
||||||
|
private command: CommandOption;
|
||||||
|
|
||||||
|
public remotes: RemotesApi;
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
domain,
|
domain,
|
||||||
@@ -254,9 +305,49 @@ export class ReuniteApiClient {
|
|||||||
domain: string;
|
domain: string;
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
version: string;
|
version: string;
|
||||||
command: 'push' | 'push-status';
|
command: CommandOption;
|
||||||
}) {
|
}) {
|
||||||
this.remotes = new RemotesApiClient(domain, apiKey, version, command);
|
this.command = command;
|
||||||
|
this.version = version;
|
||||||
|
this.apiClient = new ReuniteApiClient(this.version, this.command);
|
||||||
|
|
||||||
|
this.remotes = new RemotesApi(this.apiClient, domain, apiKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public reportSunsetWarnings(): void {
|
||||||
|
const sunsetWarnings = this.apiClient.sunsetWarnings;
|
||||||
|
|
||||||
|
if (sunsetWarnings.length) {
|
||||||
|
const [{ isSunsetExpired, sunsetDate }] = sunsetWarnings.sort(
|
||||||
|
(a: SunsetWarning, b: SunsetWarning) => {
|
||||||
|
// First, prioritize by expiration status
|
||||||
|
if (a.isSunsetExpired !== b.isSunsetExpired) {
|
||||||
|
return a.isSunsetExpired ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If both are either expired or not, sort by sunset date
|
||||||
|
return a.sunsetDate > b.sunsetDate ? 1 : -1;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateVersionMessage = `Update to the latest version by running "npm install @redocly/cli@latest".`;
|
||||||
|
|
||||||
|
if (isSunsetExpired) {
|
||||||
|
process.stdout.write(
|
||||||
|
red(
|
||||||
|
`The "${this.command}" command is not compatible with your version of Redocly CLI. ${updateVersionMessage}\n\n`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
process.stdout.write(
|
||||||
|
yellow(
|
||||||
|
`The "${
|
||||||
|
this.command
|
||||||
|
}" command will be incompatible with your version of Redocly CLI after ${sunsetDate.toLocaleString()}. ${updateVersionMessage}\n\n`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,9 @@ jest.mock('colorette', () => ({
|
|||||||
|
|
||||||
jest.mock('../../api', () => ({
|
jest.mock('../../api', () => ({
|
||||||
...jest.requireActual('../../api'),
|
...jest.requireActual('../../api'),
|
||||||
ReuniteApiClient: jest.fn().mockImplementation(function (this: any, ...args) {
|
ReuniteApi: jest.fn().mockImplementation(function (this: any, ...args) {
|
||||||
this.remotes = remotes;
|
this.remotes = remotes;
|
||||||
|
this.reportSunsetWarnings = jest.fn();
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { handlePush } from '../push';
|
import { handlePush } from '../push';
|
||||||
import { ReuniteApiClient, ReuniteApiError } from '../../api';
|
import { ReuniteApi, ReuniteApiError } from '../../api';
|
||||||
|
|
||||||
const remotes = {
|
const remotes = {
|
||||||
push: jest.fn(),
|
push: jest.fn(),
|
||||||
@@ -15,8 +15,9 @@ jest.mock('@redocly/openapi-core', () => ({
|
|||||||
|
|
||||||
jest.mock('../../api', () => ({
|
jest.mock('../../api', () => ({
|
||||||
...jest.requireActual('../../api'),
|
...jest.requireActual('../../api'),
|
||||||
ReuniteApiClient: jest.fn().mockImplementation(function (this: any, ...args) {
|
ReuniteApi: jest.fn().mockImplementation(function (this: any, ...args) {
|
||||||
this.remotes = remotes;
|
this.remotes = remotes;
|
||||||
|
this.reportSunsetWarnings = jest.fn();
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -332,7 +333,7 @@ describe('handlePush()', () => {
|
|||||||
version: 'cli-version',
|
version: 'cli-version',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(ReuniteApiClient).toBeCalledWith({
|
expect(ReuniteApi).toBeCalledWith({
|
||||||
domain: 'test-domain-from-env',
|
domain: 'test-domain-from-env',
|
||||||
apiKey: 'test-api-key',
|
apiKey: 'test-api-key',
|
||||||
version: 'cli-version',
|
version: 'cli-version',
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import * as colors from 'colorette';
|
|||||||
import { exitWithError, printExecutionTime } from '../../utils/miscellaneous';
|
import { exitWithError, printExecutionTime } from '../../utils/miscellaneous';
|
||||||
import { Spinner } from '../../utils/spinner';
|
import { Spinner } from '../../utils/spinner';
|
||||||
import { DeploymentError } from '../utils';
|
import { DeploymentError } from '../utils';
|
||||||
import { ReuniteApiClient, getApiKeys, getDomain } from '../api';
|
import { ReuniteApi, getApiKeys, getDomain } from '../api';
|
||||||
import { capitalize } from '../../utils/js-utils';
|
import { capitalize } from '../../utils/js-utils';
|
||||||
import { handleReuniteError, retryUntilConditionMet } from './utils';
|
import { handleReuniteError, retryUntilConditionMet } from './utils';
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ export async function handlePushStatus({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const apiKey = getApiKeys(domain);
|
const apiKey = getApiKeys(domain);
|
||||||
const client = new ReuniteApiClient({ domain, apiKey, version, command: 'push-status' });
|
const client = new ReuniteApi({ domain, apiKey, version, command: 'push-status' });
|
||||||
|
|
||||||
let pushResponse: PushResponse;
|
let pushResponse: PushResponse;
|
||||||
|
|
||||||
@@ -169,6 +169,8 @@ export async function handlePushStatus({
|
|||||||
}
|
}
|
||||||
printPushStatusInfo({ orgId, projectId, pushId, startedAt });
|
printPushStatusInfo({ orgId, projectId, pushId, startedAt });
|
||||||
|
|
||||||
|
client.reportSunsetWarnings();
|
||||||
|
|
||||||
const summary: PushStatusSummary = {
|
const summary: PushStatusSummary = {
|
||||||
preview: pushResponse.status.preview,
|
preview: pushResponse.status.preview,
|
||||||
production: pushResponse.isMainBranch ? pushResponse.status.production : null,
|
production: pushResponse.isMainBranch ? pushResponse.status.production : null,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { pluralize } from '@redocly/openapi-core/lib/utils';
|
|||||||
import { green, yellow } from 'colorette';
|
import { green, yellow } from 'colorette';
|
||||||
import { exitWithError, printExecutionTime } from '../../utils/miscellaneous';
|
import { exitWithError, printExecutionTime } from '../../utils/miscellaneous';
|
||||||
import { handlePushStatus } from './push-status';
|
import { handlePushStatus } from './push-status';
|
||||||
import { ReuniteApiClient, getDomain, getApiKeys } from '../api';
|
import { ReuniteApi, getDomain, getApiKeys } from '../api';
|
||||||
import { handleReuniteError } from './utils';
|
import { handleReuniteError } from './utils';
|
||||||
|
|
||||||
import type { OutputFormat } from '@redocly/openapi-core';
|
import type { OutputFormat } from '@redocly/openapi-core';
|
||||||
@@ -81,12 +81,13 @@ export async function handlePush({
|
|||||||
const author = parseCommitAuthor(argv.author);
|
const author = parseCommitAuthor(argv.author);
|
||||||
const apiKey = getApiKeys(domain);
|
const apiKey = getApiKeys(domain);
|
||||||
const filesToUpload = collectFilesToPush(argv.files || argv.apis);
|
const filesToUpload = collectFilesToPush(argv.files || argv.apis);
|
||||||
|
const commandName = 'push' as const;
|
||||||
|
|
||||||
if (!filesToUpload.length) {
|
if (!filesToUpload.length) {
|
||||||
return printExecutionTime('push', startedAt, `No files to upload`);
|
return printExecutionTime(commandName, startedAt, `No files to upload`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = new ReuniteApiClient({ domain, apiKey, version, command: 'push' });
|
const client = new ReuniteApi({ domain, apiKey, version, command: commandName });
|
||||||
const projectDefaultBranch = await client.remotes.getDefaultBranch(orgId, projectId);
|
const projectDefaultBranch = await client.remotes.getDefaultBranch(orgId, projectId);
|
||||||
const remote = await client.remotes.upsert(orgId, projectId, {
|
const remote = await client.remotes.upsert(orgId, projectId, {
|
||||||
mountBranchName: projectDefaultBranch,
|
mountBranchName: projectDefaultBranch,
|
||||||
@@ -147,7 +148,7 @@ export async function handlePush({
|
|||||||
}
|
}
|
||||||
verbose &&
|
verbose &&
|
||||||
printExecutionTime(
|
printExecutionTime(
|
||||||
'push',
|
commandName,
|
||||||
startedAt,
|
startedAt,
|
||||||
`${pluralize(
|
`${pluralize(
|
||||||
'file',
|
'file',
|
||||||
@@ -155,6 +156,8 @@ export async function handlePush({
|
|||||||
)} uploaded to organization ${orgId}, project ${projectId}. Push ID: ${id}.`
|
)} uploaded to organization ${orgId}, project ${projectId}. Push ID: ${id}.`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
client.reportSunsetWarnings();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pushId: id,
|
pushId: id,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user