Skip to content

Commit

Permalink
feat(alexa-ask): Add deploy action for Alexa (#1613)
Browse files Browse the repository at this point in the history
  • Loading branch information
hoegertn authored and RomainMuller committed Feb 1, 2019
1 parent 7d7d495 commit 0deea61
Show file tree
Hide file tree
Showing 7 changed files with 345 additions and 1 deletion.
48 changes: 48 additions & 0 deletions packages/@aws-cdk/alexa-ask/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,51 @@
```ts
const alexaAsk = require('@aws-cdk/alexa-ask');
```

### Alexa as deploy target for CodePipeline

You can deploy to Alexa using CodePipeline with the following DeployAction.

```ts
// Read the secrets from ParameterStore
const clientId = new cdk.SecretParameter(stack, 'AlexaClientId', {ssmParameter: '/Alexa/ClientId'});
const clientSecret = new cdk.SecretParameter(stack, 'AlexaClientSecret', {ssmParameter: '/Alexa/ClientSecret'});
const refreshToken = new cdk.SecretParameter(stack, 'AlexaRefreshToken', {ssmParameter: '/Alexa/RefreshToken'});

// Add deploy action
new alexa.AlexaSkillDeployAction(stack, 'DeploySkill', {
stage: deployStage,
runOrder: 1,
inputArtifact: sourceAction.outputArtifact,
clientId: clientId.value,
clientSecret: clientSecret.value,
refreshToken: refreshToken.value,
skillId: 'amzn1.ask.skill.12345678-1234-1234-1234-123456789012',
});
```

If you need manifest overrides you can specify them as `overrideArtifact` in the action.

```ts
// Deploy some CFN change set and store output
const executeChangeSetAction = new PipelineExecuteChangeSetAction(this, 'ExecuteChangesTest', {
stage: deployStage,
runOrder: 2,
stackName,
changeSetName,
outputFileName: 'overrides.json',
outputArtifactName: 'CloudFormation',
});

// Provide CFN output as manifest overrides
new AlexaSkillDeployAction(this, 'DeploySkill', {
stage: deployStage,
runOrder: 1,
inputArtifact: sourceAction.outputArtifact,
parameterOverridesArtifact: executeChangeSetAction.outputArtifact,
clientId: clientId.value,
clientSecret: clientSecret.value,
refreshToken: refreshToken.value,
skillId: 'amzn1.ask.skill.12345678-1234-1234-1234-123456789012',
});
```
1 change: 1 addition & 0 deletions packages/@aws-cdk/alexa-ask/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
// Alexa::ASK CloudFormation Resources:
export * from './ask.generated';
export * from './pipeline-actions';
67 changes: 67 additions & 0 deletions packages/@aws-cdk/alexa-ask/lib/pipeline-actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import codepipeline = require('@aws-cdk/aws-codepipeline-api');
import cdk = require('@aws-cdk/cdk');

/**
* Construction properties of the {@link AlexaSkillDeployAction Alexa deploy Action}.
*/
export interface AlexaSkillDeployActionProps extends codepipeline.CommonActionProps,
codepipeline.CommonActionConstructProps {

/**
* The client id of the developer console token
*/
clientId: cdk.Secret;

/**
* The client secret of the developer console token
*/
clientSecret: cdk.Secret;

/**
* The refresh token of the developer console token
*/
refreshToken: cdk.Secret;

/**
* The Alexa skill id
*/
skillId: string;

/**
* The source artifact containing the voice model and skill manifest
*/
inputArtifact?: codepipeline.Artifact;

/**
* An optional artifact containing overrides for the skill manifest
*/
parameterOverridesArtifact?: codepipeline.Artifact;
}

/**
* Deploys the skill to Alexa
*/
export class AlexaSkillDeployAction extends codepipeline.DeployAction {
constructor(scope: cdk.Construct, id: string, props: AlexaSkillDeployActionProps) {
super(scope, id, {
...props,
artifactBounds: {
minInputs: 1,
maxInputs: 2,
minOutputs: 0,
maxOutputs: 0,
},
owner: 'ThirdParty',
provider: 'AlexaSkillsKit',
configuration: {
ClientId: props.clientId,
ClientSecret: props.clientSecret,
RefreshToken: props.refreshToken,
SkillId: props.skillId,
},
});
if (props.parameterOverridesArtifact) {
this.addInputArtifact(props.parameterOverridesArtifact);
}
}
}
4 changes: 3 additions & 1 deletion packages/@aws-cdk/alexa-ask/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,14 @@
"pkglint": "^0.22.0"
},
"dependencies": {
"@aws-cdk/aws-codepipeline-api": "^0.22.0",
"@aws-cdk/cdk": "^0.22.0"
},
"peerDependencies": {
"@aws-cdk/aws-codepipeline-api": "^0.22.0",
"@aws-cdk/cdk": "^0.22.0"
},
"engines": {
"node": ">= 8.10.0"
}
}
}
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-codepipeline/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
},
"license": "Apache-2.0",
"devDependencies": {
"@aws-cdk/alexa-ask": "^0.22.0",
"@aws-cdk/assert": "^0.22.0",
"@aws-cdk/aws-cloudformation": "^0.22.0",
"@aws-cdk/aws-cloudtrail": "^0.22.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
{
"Resources": {
"PipelineArtifactsBucket22248F97": {
"Type": "AWS::S3::Bucket",
"DeletionPolicy": "Retain"
},
"PipelineRoleD68726F7": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "codepipeline.amazonaws.com"
}
}
],
"Version": "2012-10-17"
}
}
},
"PipelineRoleDefaultPolicyC7A05455": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": [
"s3:GetObject*",
"s3:GetBucket*",
"s3:List*",
"s3:DeleteObject*",
"s3:PutObject*",
"s3:Abort*"
],
"Effect": "Allow",
"Resource": [
{
"Fn::GetAtt": [
"PipelineArtifactsBucket22248F97",
"Arn"
]
},
{
"Fn::Join": [
"",
[
{
"Fn::GetAtt": [
"PipelineArtifactsBucket22248F97",
"Arn"
]
},
"/*"
]
]
}
]
},
{
"Action": [
"s3:GetObject*",
"s3:GetBucket*",
"s3:List*"
],
"Effect": "Allow",
"Resource": [
{
"Fn::GetAtt": [
"PipelineBucketB967BD35",
"Arn"
]
},
{
"Fn::Join": [
"",
[
{
"Fn::GetAtt": [
"PipelineBucketB967BD35",
"Arn"
]
},
"/*"
]
]
}
]
}
],
"Version": "2012-10-17"
},
"PolicyName": "PipelineRoleDefaultPolicyC7A05455",
"Roles": [
{
"Ref": "PipelineRoleD68726F7"
}
]
}
},
"PipelineC660917D": {
"Type": "AWS::CodePipeline::Pipeline",
"Properties": {
"RoleArn": {
"Fn::GetAtt": [
"PipelineRoleD68726F7",
"Arn"
]
},
"Stages": [
{
"Actions": [
{
"ActionTypeId": {
"Category": "Source",
"Owner": "AWS",
"Provider": "S3",
"Version": "1"
},
"Configuration": {
"S3Bucket": {
"Ref": "PipelineBucketB967BD35"
},
"S3ObjectKey": "key"
},
"InputArtifacts": [],
"Name": "Source",
"OutputArtifacts": [
{
"Name": "SourceArtifact"
}
],
"RunOrder": 1
}
],
"Name": "Source"
},
{
"Actions": [
{
"ActionTypeId": {
"Category": "Deploy",
"Owner": "ThirdParty",
"Provider": "AlexaSkillsKit",
"Version": "1"
},
"Configuration": {
"ClientId": "clientId",
"ClientSecret": "clientSecret",
"RefreshToken": "refreshToken",
"SkillId": "amzn1.ask.skill.12345678-1234-1234-1234-123456789012"
},
"InputArtifacts": [
{
"Name": "SourceArtifact"
}
],
"Name": "DeploySkill",
"OutputArtifacts": [],
"RunOrder": 1
}
],
"Name": "Deploy"
}
],
"ArtifactStore": {
"Location": {
"Ref": "PipelineArtifactsBucket22248F97"
},
"Type": "S3"
}
},
"DependsOn": [
"PipelineRoleD68726F7",
"PipelineRoleDefaultPolicyC7A05455"
]
},
"PipelineBucketB967BD35": {
"Type": "AWS::S3::Bucket",
"Properties": {
"VersioningConfiguration": {
"Status": "Enabled"
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import alexa = require('@aws-cdk/alexa-ask');
import s3 = require('@aws-cdk/aws-s3');
import cdk = require('@aws-cdk/cdk');
import codepipeline = require('../lib');

const app = new cdk.App();

const stack = new cdk.Stack(app, 'aws-cdk-codepipeline-alexa-deploy');

const pipeline = new codepipeline.Pipeline(stack, 'Pipeline');

const sourceStage = new codepipeline.Stage(pipeline, 'Source', { pipeline });
const bucket = new s3.Bucket(stack, 'PipelineBucket', {
versioned: true,
removalPolicy: cdk.RemovalPolicy.Destroy,
});
const sourceAction = new s3.PipelineSourceAction(stack, 'Source', {
stage: sourceStage,
outputArtifactName: 'SourceArtifact',
bucket,
bucketKey: 'key',
});

const deployStage = new codepipeline.Stage(pipeline, 'Deploy', { pipeline });

new alexa.AlexaSkillDeployAction(stack, 'DeploySkill', {
stage: deployStage,
runOrder: 1,
inputArtifact: sourceAction.outputArtifact,
clientId: new cdk.Secret('clientId'),
clientSecret: new cdk.Secret('clientSecret'),
refreshToken: new cdk.Secret('refreshToken'),
skillId: 'amzn1.ask.skill.12345678-1234-1234-1234-123456789012',
});

app.run();

0 comments on commit 0deea61

Please sign in to comment.