Skip to content

Commit

Permalink
🔀 Merge pull request #1639 from jovotech/v4/dev
Browse files Browse the repository at this point in the history
🔖 Prepare latest release
  • Loading branch information
jankoenig authored Jun 12, 2024
2 parents 4c86954 + 347ab53 commit 95a5800
Show file tree
Hide file tree
Showing 21 changed files with 487 additions and 337 deletions.
36 changes: 35 additions & 1 deletion platforms/platform-alexa/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,41 @@ You can build Alexa Skills with Jovo that make use of the Alexa Conversations di

You can use Jovo with [Alexa Skill Connections](https://developer.amazon.com/docs/alexa/custom-skills/understand-skill-connections.html) by sending a `Connections.StartConnection` directive as shown in the [official Alexa docs](https://developer.amazon.com/docs/alexa/custom-skills/use-skill-connections-to-request-tasks.html#implement-a-handler-to-return-a-connectionsstartconnection-directive-to-use-skill-connection).

For this, the Jovo Alexa integration offers convenience [output classes](https://www.jovo.tech/docs/output-classes). Below is an overview of all classes:
For example, if you want to connect to a [custom task in a specific skill](https://developer.amazon.com/en-US/docs/alexa/custom-skills/use-skill-connections-to-request-tasks.html#for-custom-task-direct-skill-connection-with-send_errors_only), you can use the `StartConnectionOutput` class provided by the Jovo Alexa integration.

```typescript
import { StartConnectionOutput, OnCompletion } from '@jovotech/platform-alexa';
// ...

someHandler() {
// ...

return this.$send(StartConnectionOutput, {
taskName: {
amazonPredefinedTask: false,
name: 'CountDown',
},
// Input for the task
input: {
upperLimit: 10,
lowerLimit: 1,
},
// Decides whether session is picked up after task
onCompletion: OnCompletion.SendErrorsOnly,
token: '<your-token>',
// defaults to 1
taskVersion: 1,
// This is mandatory in case taskName.amazonPredefinedTask is false
providerSkillId: '<skill-id>',
});
}
```

The Output Options can be changed to create a [managed skill connection](https://developer.amazon.com/en-US/docs/alexa/custom-skills/use-skill-connections-to-request-tasks.html#for-managed-skill-connection), by setting `taskName.amazonPredefinedTask` to true and omitting `providerSkillId`.

In case the session is supposed to be [resumed](https://developer.amazon.com/en-US/docs/alexa/custom-skills/use-skill-connections-to-request-tasks.html#return-connectionsstartconnection-directive-with-resume_session-set-explicitly-or-by-default) after the task is handled, `onCompletion` can be changed to `OnCompletion.ResumeSession`.

For some specific connections, the Jovo Alexa integration offers convenience [output classes](https://www.jovo.tech/docs/output-classes). Below is an overview of all classes:

- [`ConnectionAskForPermissionConsentOutput`](https://github.com/jovotech/jovo-framework/tree/v4/latest/platforms/platform-alexa/src/output/templates/ConnectionAskForPermissionConsentOutput.ts)
- [`ConnectionLinkAppOutput`](https://github.com/jovotech/jovo-framework/tree/v4/latest/platforms/platform-alexa/src/output/templates/ConnectionLinkAppOutput.ts)
Expand Down
40 changes: 39 additions & 1 deletion platforms/platform-alexa/docs/cli-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ The Alexa CLI plugin hooks into the following commands:
- [`deploy`](#deploy): Deploy project files to the Alexa Developer Console
- [`get`](#get): Synchronize your local project files with the Alexa Developer Console

Also it provides the following platform specific commands:

- [`validate:alexa`](#validate): Trigger the Alexa Skill Validation
- [`certify:alexa`](#certify): Trigger the Alexa Skill Certification

## build

The Alexa CLI plugin hooks into the `build` command and creates a `platform.alexa` folder inside the `build` directory in the root of your Jovo project. [Learn more about the `build` command here](https://www.jovo.tech/docs/build-command).
Expand Down Expand Up @@ -132,4 +137,37 @@ $ jovo get:platform alexa

# Turn Alexa Interaction Model into Jovo Model
$ jovo build:platform alexa --reverse
```
```

## validate

The Alexa CLI plugin provides a command to easily trigger a Skill Validation.

```sh
$ jovo verify:alexa
```

After successfully triggering the validation, you can check the status in the [Alexa Developer Console](https://developer.amazon.com/alexa/console/ask#/).

| Flag | Description | Examples |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
| `--skill-stage` | Either `development`, `live` or `certification` depending on what skill stage is to be validated. Default is `development` | `jovo validate:alexa --skill-stage development` | | |
| `--skill-id` | The skillId of the to be validated skill. If not provided, will be taken from the stage in the project configuration. [Learn more about ASK skillId configuration here](./project-config.md#skillid) | `jovo validate:alexa --skill-id amzn1.ask.skill.123example` |
| `--ask-profile` | Deploy to using the specified ASK profile. If not provided as flag, will be taken from project configuration. [Learn more about ASK profile configuration here](./project-config.md#askprofile) | `jovo validate:alexa --ask-profile default` |
| `--locales` | List of locales in which to validate the skill. If not provided, will do for all locales in project configuration. [Learn more about locales configuration here](./project-config.md#locales) | `jovo validate:alexa --locales en-US de-DE` |

## certify

The Alexa CLI plugin provides a command to easily trigger a Skill Certification.

```sh
$ jovo certify:alexa
```

After successfully triggering the certification, you can check the status of the certification in the [Alexa Developer Console](https://developer.amazon.com/alexa/console/ask#/).

| Flag | Description | Examples |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
| `--skill-id` | The skillId of the to be validated skill. If not provided, will be taken from the stage in the project configuration. [Learn more about ASK skillId configuration here](./project-config.md#skillid) | `jovo certify:alexa --skill-id amzn1.ask.skill.123example` |
| `--ask-profile` | Deploy to using the specified ASK profile. If not provided as flag, will be taken from project configuration. [Learn more about ASK profile configuration here](./project-config.md#askprofile) | `jovo certify:alexa --ask-profile default` |
| `--publication-method` | Either `MANUAL_PUBLISHING` or `AUTO_PUBLISHING`. Default is `MANUAL_PUBLISHING`. [Learn more about publication methods](https://developer.amazon.com/en-US/docs/alexa/smapi/ask-cli-command-reference.html#submit-skill-for-certification-subcommand) | `jovo validate:alexa --publication-method AUTO_PUBLISHING` |
44 changes: 44 additions & 0 deletions platforms/platform-alexa/src/cli/commands/CertifyCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { JovoCliError, MAGNIFYING_GLASS, PluginCommand, Task, flags } from '@jovotech/cli-core';
import * as smapi from '../smapi';
import { AlexaCli } from '..';
import { PublicationMethodLike, PublicationMethod } from '../interfaces';

export class CertifyCommand extends PluginCommand {
$plugin!: AlexaCli;
static id = 'certify:alexa';
static description = 'This submits an alexa skill to certification';
static examples: string[] = ['jovo certify:alexa'];
static flags = {
...PluginCommand.flags,
'skill-id': flags.string({ char: 's', description: 'Alexa Skill ID' }),
'ask-profile': flags.string({
description: 'Name of used ASK profile',
}),
'publication-method': flags.string({
options: Object.values(PublicationMethod),
default: PublicationMethod.MANUAL_PUBLISHING,
}),
};
static args = [];

async run(): Promise<void> {
const { flags } = this.parse(CertifyCommand);
const skillId = flags['skill-id'] || this.$plugin.config.skillId;
const askProfile = flags['ask-profile'] || this.$plugin.config.askProfile || 'default';
const publicationMethod: PublicationMethodLike = flags['publication-method'];

const certifyTask: Task = new Task(
`${MAGNIFYING_GLASS} Submitting Alexa Skill ${skillId} to Certification`,
async () => {
if (!skillId)
throw new JovoCliError({
message: 'Cannot submit Skill to Certification without skillId',
hint: 'Either add a skillId to the stage in the project configuration or add the --skill-id flag',
});

return smapi.submitSkillForCertification(skillId, publicationMethod, askProfile);
},
);
await certifyTask.run();
}
}
63 changes: 63 additions & 0 deletions platforms/platform-alexa/src/cli/commands/ValidateCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {
JovoCliError,
Log,
MAGNIFYING_GLASS,
PluginCommand,
Task,
flags,
} from '@jovotech/cli-core';
import * as smapi from '../smapi';
import { AlexaCli } from '..';

export class ValidateCommand extends PluginCommand {
$plugin!: AlexaCli;
static id = 'validate:alexa';
static description = 'This submits a skill validation';
static examples: string[] = ['jovo validate:alexa'];
static flags = {
'skill-stage': flags.string({
description: 'Alexa Skill Stage',
options: ['development', 'live', 'certification'],
default: 'development',
}),
'skill-id': flags.string({ char: 's', description: 'Alexa Skill ID' }),
'ask-profile': flags.string({
description: 'Name of used ASK profile',
}),
'locales': flags.string({ multiple: true, char: 'l' }),
...PluginCommand.flags,
};
static args = [];

async run(): Promise<void> {
const { flags } = this.parse(ValidateCommand);
const skillId = flags['skill-id'] || this.$plugin.config.skillId;
const askProfile = flags['ask-profile'] || this.$plugin.config.askProfile || 'default';
const locales =
flags.locales ||
Object.values(this.$plugin.config.locales || {}).reduce(
(prev, curr) => [...prev, ...curr],
[],
);

const validateTask: Task = new Task(
`${MAGNIFYING_GLASS} Submitting Alexa Skill ${skillId} to Validation`,
async () => {
if (!skillId)
throw new JovoCliError({
message: 'Cannot submit Skill Validation without skillId',
hint: 'Either add a skillId to the stage in the project configuration or add the --skill-id flag',
});

const validationResponse = await smapi.submitSkillValidation(
skillId,
locales,
flags['skill-stage'],
askProfile,
);
return `Started Validation with id ${validationResponse.id}`;
},
);
await validateTask.run();
}
}
7 changes: 7 additions & 0 deletions platforms/platform-alexa/src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { NewContext } from '@jovotech/cli-command-new';
import {
JovoCliPlugin,
Log,
PluginCommand,
PluginHook,
PluginType,
promptSupportedLocales,
Expand All @@ -15,6 +16,8 @@ import { DeployHook } from './hooks/DeployHook';
import { GetHook } from './hooks/GetHook';
import { NewHook } from './hooks/NewHook';
import { AlexaCliConfig, AlexaConversationsConfig, SupportedLocalesType } from './interfaces';
import { CertifyCommand } from './commands/CertifyCommand';
import { ValidateCommand } from './commands/ValidateCommand';

export type AlexaCliInitConfig =
| RequiredOnlyWhere<AlexaCliConfig, 'conversations.enabled'>
Expand Down Expand Up @@ -105,6 +108,10 @@ export class AlexaCli extends JovoCliPlugin<AlexaCliConfig> {
return [BuildHook, GetHook, DeployHook, NewHook];
}

getCommands(): (typeof PluginCommand)[] {
return [CertifyCommand, ValidateCommand];
}

/**
* The base path to platform's build folder
*/
Expand Down
16 changes: 15 additions & 1 deletion platforms/platform-alexa/src/cli/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PluginConfig, PluginContext } from '@jovotech/cli-core';
import { UnknownObject } from '@jovotech/framework';
import { EnumLike, UnknownObject } from '@jovotech/framework';
import { ConversationsTarget } from '../interfaces';

import { SupportedLocales } from './constants';
Expand Down Expand Up @@ -116,3 +116,17 @@ export interface SkillStatusResponse {
};
interactionModel?: UnknownObject;
}

export enum PublicationMethod {
MANUAL_PUBLISHING = 'MANUAL_PUBLISHING',
AUTO_PUBLISHING = 'AUTO_PUBLISHING',
}

export type PublicationMethodLike = EnumLike<PublicationMethod> | string;

export type ValidationStatus = 'SUCCEEDED' | 'FAILED' | 'IN_PROGRESS';

export interface SkillValidationResponse {
id: string;
status: ValidationStatus;
}
46 changes: 45 additions & 1 deletion platforms/platform-alexa/src/cli/smapi/SkillManagement.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { JovoCliError, wait } from '@jovotech/cli-core';
import { AskSkillList, SkillStatusError, SkillStatusResponse } from '../interfaces';
import {
AskSkillList,
SkillStatusError,
SkillStatusResponse,
SkillValidationResponse,
} from '../interfaces';
import { execAskCommand } from '../utilities';
import { PublicationMethodLike } from '../interfaces';

export async function listSkills(askProfile?: string): Promise<AskSkillList> {
const { stdout } = await execAskCommand(
Expand Down Expand Up @@ -45,3 +51,41 @@ export async function getSkillStatus(skillId: string, askProfile?: string): Prom
}
}
}

export async function submitSkillForCertification(
skillId: string,
publicationMethod: PublicationMethodLike,
askProfile?: string,
): Promise<string | undefined> {
const { stdout } = await execAskCommand(
'smapiSubmitSkillForCertification',
[
'ask smapi submit-skill-for-certification',
`-s ${skillId}`,
`--publication-method ${publicationMethod}`,
],
askProfile,
);

return stdout;
}

export async function submitSkillValidation(
skillId: string,
locales: string[],
stage: string,
askProfile?: string,
): Promise<SkillValidationResponse> {
const { stdout } = await execAskCommand(
'smapiSubmitSkillValidation',
[
'ask smapi submit-skill-validation',
`-s ${skillId}`,
`--stage ${stage}`,
`--locales ${locales.join(' ')}`,
],
askProfile,
);

return JSON.parse(stdout!);
}
1 change: 1 addition & 0 deletions platforms/platform-alexa/src/output/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export * from './common/AsinProduct';
export * from './common/ConnectionPostalAddress';
export * from './common/ConsentLevel';
export * from './common/PermissionScope';
export * from './common/OnCompletion';
export * from './dialog/DialogConfirmIntentDirective';
export * from './dialog/DialogConfirmSlotDirective';
export * from './dialog/DialogDelegateDirective';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { BaseOutput, Output, OutputOptions, OutputTemplate } from '@jovotech/framework';
import { AsinProduct } from '../models';
import { OnCompletion } from '../models/common/OnCompletion';
import { StartConnectionOutput } from './StartConnectionOutput';

export interface ConnectionAddToShoppingCartOutputOptions extends OutputOptions {
shouldEndSession?: boolean;
Expand All @@ -19,33 +20,15 @@ export class ConnectionAddToShoppingCartOutput extends BaseOutput<ConnectionAddT
}

build(): OutputTemplate | OutputTemplate[] {
const shouldEndSession =
this.options.onCompletion === OnCompletion.SendErrorsOnly
? true
: this.options.shouldEndSession;

return {
message: this.options.message,
platforms: {
alexa: {
nativeResponse: {
response: {
shouldEndSession,
directives: [
{
type: 'Connections.StartConnection',
uri: 'connection://AMAZON.AddToShoppingCart/1',
input: {
products: this.options.products,
},
token: this.options.token,
onCompletion: this.options.onCompletion,
},
],
},
},
},
return new StartConnectionOutput(this.jovo, {
taskName: { name: 'AddToShoppingCart', amazonPredefinedTask: true },
taskVersion: 1,
shouldEndSession: this.options.shouldEndSession,
onCompletion: this.options.onCompletion,
input: {
products: this.options.products,
},
};
token: this.options.token,
}).build();
}
}
Loading

0 comments on commit 95a5800

Please sign in to comment.