@sprucelabs/spruce-cli
Version:
Command line interface for building Spruce skills.
319 lines • 16.6 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = __importDefault(require("path"));
const mercury_types_1 = require("@sprucelabs/mercury-types");
const spruce_event_utils_1 = require("@sprucelabs/spruce-event-utils");
const spruce_skill_utils_1 = require("@sprucelabs/spruce-skill-utils");
const test_utils_1 = require("@sprucelabs/test-utils");
const EventWriter_1 = require("../../../features/event/writers/EventWriter");
const LintService_1 = __importDefault(require("../../../services/LintService"));
const AbstractEventTest_1 = __importDefault(require("../../../tests/AbstractEventTest"));
const test_utility_1 = __importDefault(require("../../../tests/utilities/test.utility"));
class KeepingEventsInSyncTest extends AbstractEventTest_1.default {
static randomVersion = 'v2020_01_01';
static get todaysVersion() {
return spruce_skill_utils_1.versionUtil.generateVersion();
}
static async syncingSchemasWithDisconnectedStopsWithError() {
await this.FeatureFixture().installCachedFeatures('events');
await this.syncCoreEventsPretendingToBeMercuryTypes();
const results = await this.Action('schema', 'sync').execute({});
const match = test_utility_1.default.assertFileByNameInGeneratedFiles('sendMessageEmitPayload.schema.ts', results.files);
test_utils_1.assert.isTrue(spruce_skill_utils_1.diskUtil.doesFileExist(match));
const client = await this.getMercuryFixture().connectToApi({
shouldAuthAsCurrentSkill: true,
});
await client.disconnect();
const results2 = await this.Action('schema', 'sync').execute({});
test_utils_1.assert.isTruthy(results2.errors);
test_utils_1.assert.isTrue(spruce_skill_utils_1.diskUtil.doesFileExist(match));
}
static async syncingSchemasDoesNotSyncEventSchemasIfEventsNotInstalled() {
await this.FeatureFixture().installCachedFeatures('schemas');
const results = await this.Action('schema', 'sync').execute({});
test_utils_1.assert.doesThrow(() => this.assertCorePayloadSchemasAreCreated(results));
}
static async canGetNumberOfEventsBackFromHealthCheck() {
const cli = await this.FeatureFixture().installCachedFeatures('events');
LintService_1.default.enableLinting();
const results = await this.Action('event', 'sync').execute({});
test_utils_1.assert.isFalsy(results.errors);
await this.Service('build').build();
const health = await cli.checkHealth({ shouldRunOnSourceFiles: false });
test_utils_1.assert.isTruthy(health.skill);
test_utils_1.assert.isFalsy(health.skill.errors);
test_utils_1.assert.isTruthy(health.event);
test_utils_1.assert.isEqual(health.event.status, 'passed');
test_utils_1.assert.isTruthy(health.event.contracts);
test_utils_1.assert.isAbove(health.event.contracts.length, 0);
}
static async syncsEventsFromOtherSkills() {
const { skillFixture, skill2 } = await this.seedDummySkillRegisterCurrentSkillAndInstallToOrg();
const eventName = `my-new-event::${this.todaysVersion.constValue}`;
const fqen = `${skill2.slug}.my-new-event::${this.todaysVersion.constValue}`;
const description = (0, test_utils_1.generateId)() + '"' + '"';
const aiInstructions = (0, test_utils_1.generateId)() + '"' + '"';
await skillFixture.registerEventContract(skill2, {
eventSignatures: {
[eventName]: {
description,
aiInstructions,
emitPayloadSchema: (0, spruce_event_utils_1.buildEmitTargetAndPayloadSchema)({
eventName: 'my-new-event',
targetSchema: spruce_event_utils_1.eventTargetSchema,
payloadSchema: {
id: 'myNewEventEmitPayloadId',
fields: { onlyField: { type: 'text' } },
},
}),
responsePayloadSchema: {
id: 'myNewEventResponsePayloadId',
fields: {},
},
emitPermissionContract: (0, mercury_types_1.buildPermissionContract)({
id: 'myNewEventEmitPermissionContract',
name: 'My new event emit permissionContract',
permissions: [
{
id: 'can-emit',
name: 'Can emit my new event',
defaults: {
guest: {
default: true,
},
},
},
],
}),
listenPermissionContract: (0, mercury_types_1.buildPermissionContract)({
id: 'myNewEventListenPermissionContract',
name: 'My new event listen permissionContract',
permissions: [
{
id: 'can-listen',
name: 'Can emit my new event',
defaults: {
guest: {
default: true,
},
},
},
],
}),
},
},
});
this.Service('dependency').add({
id: skill2.id,
namespace: skill2.slug,
});
const results = await this.Action('event', 'sync').execute({});
const match = test_utility_1.default.assertFileByNameInGeneratedFiles(`myNewEvent.${this.todaysVersion.dirValue}.contract.ts`, results.files);
test_utils_1.assert.doesInclude(match, `${spruce_skill_utils_1.namesUtil.toCamel(skill2.slug)}${path_1.default.sep}myNewEvent.${this.todaysVersion.dirValue}.contract.ts`);
const contract = (await this.Service('import').importDefault(match));
const sig = spruce_event_utils_1.eventContractUtil.getSignatureByName(contract, fqen);
test_utils_1.assert.isTruthy(sig.emitPayloadSchema);
test_utils_1.assert.isTruthy(
//@ts-ignore
sig.emitPayloadSchema.fields?.payload?.options?.schema?.id, 'myNewEventEmitPayloadId');
test_utils_1.assert.isTruthy(sig.responsePayloadSchema?.id, 'myNewEventResponsePayloadId');
test_utils_1.assert.isTruthy(sig.emitPermissionContract);
test_utils_1.assert.isEqual(sig.emitPermissionContract.id, `${skill2.slug}.myNewEventEmitPermissionContract`);
test_utils_1.assert.isEqual(sig.emitPermissionContract.permissions[0].id, 'can-emit');
test_utils_1.assert.isTruthy(sig.listenPermissionContract);
test_utils_1.assert.isEqual(sig.listenPermissionContract.id, `${skill2.slug}.myNewEventListenPermissionContract`);
test_utils_1.assert.isEqual(sig.listenPermissionContract.permissions[0].id, 'can-listen');
test_utils_1.assert.isEqual(sig.description, description, 'description missing');
test_utils_1.assert.isEqual(sig.aiInstructions, aiInstructions, 'aiInstructions missing');
}
static async twoSkillsWithSameEventCanBeSynced() {
const { skill2, skillFixture, orgFixture, org } = await this.seedDummySkillRegisterCurrentSkillAndInstallToOrg();
const skill3 = await skillFixture.seedDemoSkill({
name: 'a third skill',
});
await orgFixture.installSkillAtOrganization(skill3.id, org.id);
const eventName = `my-new-event::${this.todaysVersion.constValue}`;
await skillFixture.registerEventContract(skill2, {
eventSignatures: {
[eventName]: {
emitPayloadSchema: (0, spruce_event_utils_1.buildEmitTargetAndPayloadSchema)({
eventName: 'my-new-event',
targetSchema: spruce_event_utils_1.eventTargetSchema,
}),
},
},
});
await skillFixture.registerEventContract(skill3, {
eventSignatures: {
[eventName]: {
emitPayloadSchema: (0, spruce_event_utils_1.buildEmitTargetAndPayloadSchema)({
eventName: 'my-new-event',
targetSchema: spruce_event_utils_1.eventTargetSchema,
}),
},
},
});
await this.Service('dependency').set([
{
id: skill2.id,
namespace: skill2.slug,
},
{
id: skill3.id,
namespace: skill3.slug,
},
]);
const results = await this.Action('event', 'sync').execute({});
const contract = test_utility_1.default.assertFileByNameInGeneratedFiles('events.contract.ts', results.files);
await this.Service('typeChecker').check(contract);
}
static async skillWithSameEventNameButDifferentVersionsCanBeSynced() {
const { skill2, skillFixture } = await this.seedDummySkillRegisterCurrentSkillAndInstallToOrg();
const eventName = `my-new-event::${this.todaysVersion.constValue}`;
const eventName2 = `my-new-event::${this.randomVersion}`;
await skillFixture.registerEventContract(skill2, {
eventSignatures: {
[eventName]: {
emitPayloadSchema: (0, spruce_event_utils_1.buildEmitTargetAndPayloadSchema)({
eventName: 'my-new-event',
targetSchema: spruce_event_utils_1.eventTargetSchema,
}),
},
[eventName2]: {
emitPayloadSchema: (0, spruce_event_utils_1.buildEmitTargetAndPayloadSchema)({
eventName: 'my-new-event',
targetSchema: spruce_event_utils_1.eventTargetSchema,
}),
},
},
});
await this.Service('dependency').add({
id: skill2.id,
namespace: skill2.slug,
});
const results = await this.Action('event', 'sync').execute({});
const contract = test_utility_1.default.assertFileByNameInGeneratedFiles('events.contract.ts', results.files);
await this.Service('typeChecker').check(contract);
}
static async unRegisteredEventsAreRemoved() {
const { skillFixture, syncResults, skill2, contractFileName } = await this.seedSkillsAndRegisterAndSyncEvents();
await this.assertValidActionResponseFiles(syncResults);
await skillFixture.unRegisterEvents(skill2, {
shouldUnregisterAll: true,
});
const eventContract = test_utility_1.default.assertFileByNameInGeneratedFiles(contractFileName, syncResults.files);
test_utils_1.assert.isTrue(spruce_skill_utils_1.diskUtil.doesFileExist(eventContract));
await this.Action('event', 'sync').execute({});
test_utils_1.assert.isFalse(spruce_skill_utils_1.diskUtil.doesFileExist(eventContract));
const dirname = path_1.default.dirname(eventContract);
test_utils_1.assert.isFalse(spruce_skill_utils_1.diskUtil.doesDirExist(dirname));
}
static async syncCoreEventsPretendingToBeMercuryTypes() {
const results = await this.Action('event', 'sync').execute({
shouldSyncOnlyCoreEvents: true,
eventBuilderFile: '../../../builder',
skillEventContractTypesFile: '../../builder',
});
const builder = `
export function buildEventContract(..._: any[]):any { return _[0] }
export function buildPermissionContract(..._: any[]):any { return _[0] }
`;
spruce_skill_utils_1.diskUtil.writeFile(this.resolvePath('src', 'builder.ts'), builder);
await this.Service('pkg').uninstall([
'@sprucelabs/mercury-types',
'@sprucelabs/mercury-client',
'@sprucelabs/spruce-event-plugin',
]);
return results;
}
static async seedSkillsAndRegisterAndSyncEvents(signature) {
const { skill2, skillFixture, cli } = await this.seedDummySkillRegisterCurrentSkillAndInstallToOrg();
const { results, filename } = await this.registerEventAndSync(skill2, signature);
return {
skillFixture,
syncResults: results,
cli,
skill2,
contractFileName: filename,
};
}
static async registerEventAndSync(skill, signature) {
const skillFixture = this.getSkillFixture();
const stamp = new Date().getTime();
const eventName = `cleanup-event-test-${stamp}::${this.todaysVersion.constValue}`;
const filename = (0, EventWriter_1.generateEventContractFileName)({
nameCamel: `cleanupEventTest${stamp}`,
version: this.todaysVersion.constValue,
});
await skillFixture.registerEventContract(skill, {
eventSignatures: {
[eventName]: {
emitPayloadSchema: (0, spruce_event_utils_1.buildEmitTargetAndPayloadSchema)({
eventName,
targetSchema: spruce_event_utils_1.eventTargetSchema,
}),
...signature,
},
},
});
await this.Service('dependency').add({
id: skill.id,
namespace: skill.slug,
});
const results = await this.Action('event', 'sync').execute({});
return { results, filename };
}
static assertCorePayloadSchemasAreCreated(results, shouldHaveWritten = true) {
const filesToCheck = [
{
name: `unregisterListenersEmitTargetAndPayload.schema.ts`,
path: `schemas${path_1.default.sep}${spruce_skill_utils_1.MERCURY_API_NAMESPACE}`,
},
];
this.assertFilesWereGenerated(filesToCheck, results, shouldHaveWritten);
}
static assertFilesWereGenerated(filesToCheck, results, shouldHaveWritten = true) {
for (const file of filesToCheck) {
const expected = this.resolveHashSprucePath('schemas/mercury/v2020_12_25', file.name);
const doesExist = spruce_skill_utils_1.diskUtil.doesFileExist(expected);
if (shouldHaveWritten) {
test_utils_1.assert.isTrue(doesExist, `Expected to find ${file} on the filesystem.`);
}
else {
test_utils_1.assert.isFalse(doesExist, `Should not have written ${file}.`);
}
}
}
}
exports.default = KeepingEventsInSyncTest;
__decorate([
test_utils_1.test.skip('find how to simulate connection errors')
], KeepingEventsInSyncTest, "syncingSchemasWithDisconnectedStopsWithError", null);
__decorate([
(0, test_utils_1.test)()
], KeepingEventsInSyncTest, "syncingSchemasDoesNotSyncEventSchemasIfEventsNotInstalled", null);
__decorate([
(0, test_utils_1.test)()
], KeepingEventsInSyncTest, "canGetNumberOfEventsBackFromHealthCheck", null);
__decorate([
(0, test_utils_1.test)()
], KeepingEventsInSyncTest, "syncsEventsFromOtherSkills", null);
__decorate([
(0, test_utils_1.test)()
], KeepingEventsInSyncTest, "twoSkillsWithSameEventCanBeSynced", null);
__decorate([
(0, test_utils_1.test)()
], KeepingEventsInSyncTest, "skillWithSameEventNameButDifferentVersionsCanBeSynced", null);
__decorate([
(0, test_utils_1.test)()
], KeepingEventsInSyncTest, "unRegisteredEventsAreRemoved", null);
//# sourceMappingURL=KeepingEventsInSync2.test.js.map