-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
387 additions
and
130 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
import {Command, flags} from '@oclif/command'; | ||
import {cli} from 'cli-ux'; | ||
import {ReadStream} from 'fs'; | ||
import {dedent} from 'ts-dedent'; | ||
import {cwd} from 'process'; | ||
import {Config} from '../../../lib/config/config'; | ||
import {Project} from '../../../lib/project/project'; | ||
import {SnapshotFactory} from '../../../lib/snapshot/snapshotFactory'; | ||
import { | ||
snapshotSynchronizationUrl, | ||
snapshotUrl, | ||
SnapshotUrlOptionsArgs, | ||
} from '../../../lib/platform/url'; | ||
import {Snapshot} from '../../../lib/snapshot/snapshot'; | ||
import {red, green} from 'chalk'; | ||
import {normalize} from 'path'; | ||
|
||
export interface CustomFile extends ReadStream { | ||
type?: string; | ||
} | ||
|
||
export default abstract class SnapshotBase extends Command { | ||
public static description = 'Create and validate a snapshot'; | ||
|
||
public static flags = { | ||
target: flags.string({ | ||
char: 't', | ||
description: | ||
'The unique identifier of the organization where to send the changes. If not specified, the organization you are connected to will be used.', | ||
helpValue: 'destinationorganizationg7dg3gd', | ||
required: false, | ||
}), | ||
projectPath: flags.string({ | ||
char: 'p', | ||
description: 'The path to your Coveo project.', | ||
helpValue: '/Users/Me/my-project', | ||
default: cwd(), | ||
required: false, | ||
}), | ||
deleteMissingResources: flags.boolean({ | ||
char: 'd', | ||
description: 'Whether or not to show resources to delete', | ||
default: false, | ||
required: false, | ||
}), | ||
}; | ||
|
||
public static hidden = true; | ||
|
||
protected async dryRun() { | ||
const project = new Project(normalize(this.flags.projectPath)); | ||
|
||
cli.action.start('Creating snapshot'); | ||
const snapshot = await this.createSnapshotFromProject(project); | ||
|
||
cli.action.start('Validating snapshot'); | ||
const isValid = await this.validateSnapshot(snapshot); | ||
|
||
cli.action.stop(isValid ? green('✔') : red.bold('!')); | ||
return {isValid, snapshot, project}; | ||
} | ||
|
||
protected async createSnapshotFromProject( | ||
project: Project | ||
): Promise<Snapshot> { | ||
const pathToZip = await project.compressResources(); | ||
const targetOrg = await this.getTargetOrg(); | ||
|
||
return await SnapshotFactory.createFromZip(pathToZip, targetOrg); | ||
} | ||
|
||
protected async validateSnapshot(snapshot: Snapshot): Promise<boolean> { | ||
const {isValid} = await snapshot.validate( | ||
this.flags.deleteMissingResources | ||
); | ||
|
||
if (!isValid) { | ||
await this.handleReportWithErrors(snapshot); | ||
} | ||
|
||
return isValid; | ||
} | ||
|
||
protected async getTargetOrg() { | ||
if (this.flags.target) { | ||
return this.flags.target; | ||
} | ||
const cfg = await this.configuration.get(); | ||
return cfg.organization; | ||
} | ||
|
||
protected async handleReportWithErrors(snapshot: Snapshot) { | ||
// TODO: CDX-362: handle invalid snapshot cases | ||
const pathToReport = snapshot.saveDetailedReport(this.flags.projectPath); | ||
const report = snapshot.latestReport; | ||
|
||
if (snapshot.requiresSynchronization()) { | ||
const synchronizationPlanUrl = await this.getSynchronizationPage( | ||
snapshot | ||
); | ||
this.warn( | ||
dedent` | ||
Some conflicts were detected while comparing changes between the snapshot and the target organization. | ||
Click on the URL below to synchronize your snapshot with your organization before running the command again. | ||
${synchronizationPlanUrl} | ||
` | ||
); | ||
return; | ||
} | ||
|
||
const snapshotUrl = await this.getSnapshotPage(snapshot); | ||
|
||
this.error( | ||
dedent`Invalid snapshot - ${report.resultCode}. | ||
Detailed report saved at ${pathToReport}. | ||
You can also use this link to view the snapshot in the Coveo Admin Console | ||
${snapshotUrl}` | ||
); | ||
} | ||
|
||
private get flags() { | ||
const {flags} = this.parse(this.ctor as typeof SnapshotBase); | ||
return flags; | ||
} | ||
|
||
private get configuration() { | ||
return new Config(this.config.configDir, this.error); | ||
} | ||
|
||
private async getSnapshotPage(snapshot: Snapshot) { | ||
const options = await this.getSnapshotUrlOptions(snapshot); | ||
return snapshotUrl(options); | ||
} | ||
|
||
private async getSynchronizationPage(snapshot: Snapshot) { | ||
const options = await this.getSnapshotUrlOptions(snapshot); | ||
return snapshotSynchronizationUrl(options); | ||
} | ||
|
||
private async getSnapshotUrlOptions( | ||
snapshot: Snapshot | ||
): Promise<SnapshotUrlOptionsArgs> { | ||
const {environment} = await this.configuration.get(); | ||
return { | ||
environment, | ||
targetOrgId: snapshot.targetId, | ||
snapshotId: snapshot.id, | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import {cli} from 'cli-ux'; | ||
import {ReadStream} from 'fs'; | ||
import { | ||
IsAuthenticated, | ||
Preconditions, | ||
} from '../../../lib/decorators/preconditions'; | ||
import {Snapshot} from '../../../lib/snapshot/snapshot'; | ||
import {red, green, bold} from 'chalk'; | ||
import SnapshotBase from './orgConfigBase'; | ||
|
||
export interface CustomFile extends ReadStream { | ||
type?: string; | ||
} | ||
|
||
export default class Push extends SnapshotBase { | ||
public static description = | ||
'Preview, validate and deploy your changes to the destination org'; | ||
|
||
public static flags = { | ||
...SnapshotBase.flags, | ||
}; | ||
|
||
public static hidden = true; | ||
|
||
@Preconditions(IsAuthenticated()) | ||
public async run() { | ||
const {isValid, snapshot, project} = await this.dryRun(); | ||
|
||
await snapshot.preview(); | ||
|
||
if (isValid) { | ||
await this.handleValidReport(snapshot); | ||
await snapshot.delete(); | ||
} | ||
|
||
project.deleteTemporaryZipFile(); | ||
} | ||
|
||
private async handleValidReport(snapshot: Snapshot) { | ||
if (!snapshot.hasChangedResources()) { | ||
return; | ||
} | ||
const targetOrg = await this.getTargetOrg(); | ||
const canBeApplied = await cli.confirm( | ||
`\nWould you like to apply these changes to the org ${bold( | ||
targetOrg | ||
)}? (y/n)` | ||
); | ||
|
||
if (canBeApplied) { | ||
await this.applySnapshot(snapshot); | ||
} | ||
} | ||
|
||
private async applySnapshot(snapshot: Snapshot) { | ||
cli.action.start('Applying snapshot'); | ||
const {flags} = this.parse(Push); | ||
const {isValid} = await snapshot.apply(flags.deleteMissingResources); | ||
|
||
if (!isValid) { | ||
await this.handleReportWithErrors(snapshot); | ||
} | ||
|
||
cli.action.stop(isValid ? green('✔') : red.bold('!')); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { | ||
snapshotSynchronizationUrl, | ||
snapshotUrl, | ||
SnapshotUrlOptionsArgs, | ||
} from './url'; | ||
|
||
describe('url', () => { | ||
const getSnapshotUrlOptions = (): SnapshotUrlOptionsArgs => { | ||
return { | ||
environment: 'prod', | ||
targetOrgId: 'foo', | ||
snapshotId: 'bar', | ||
}; | ||
}; | ||
|
||
it('#snapshotUrl should return the url to the snapshot page', () => { | ||
const options = getSnapshotUrlOptions(); | ||
expect(snapshotUrl(options)).toEqual( | ||
'https://platform.cloud.coveo.com/admin/#foo/organization/resource-snapshots/bar' | ||
); | ||
}); | ||
|
||
it('#snapshotSynchronizationUrl should return the url to the snapshot synchronization page', () => { | ||
const options = getSnapshotUrlOptions(); | ||
expect(snapshotSynchronizationUrl(options)).toEqual( | ||
'https://platform.cloud.coveo.com/admin/#foo/organization/resource-snapshots/bar/synchronization' | ||
); | ||
}); | ||
}); |
Oops, something went wrong.