Alexa configuration deployment (staging and product) practice - alexa-skills-kit

Hello I am new to Alexa Skill Kit deployment using ask-cli. I just want to know if there are any deployment practices in place where we have different configurations i.e skills.json and .ask/config
For example, I have a repository some-alexa-skill with 2 branches: staging and production.
staging has this configuration for the skills.json
{
"skillManifest": {
"publishingInformation": {
"locales": {
"en-US": {
"name": "staging"
}
},
"isAvailableWorldwide": true,
"distributionCountries": []
},
"apis": {
"custom": {
"endpoint": {
"uri": "staging",
"sourceDir": "lambda/custom"
}
}
},
"manifestVersion": "1.0"
}
}
while production has this:
{
"skillManifest": {
"publishingInformation": {
"locales": {
"en-US": {
"name": "production"
}
},
"isAvailableWorldwide": true,
"distributionCountries": []
},
"apis": {
"custom": {
"endpoint": {
"uri": "production",
"sourceDir": "lambda/custom"
}
}
},
"manifestVersion": "1.0"
}
}
As I can observe skill.json should be "ignored" in the git respository since it will be replaced whenever merges occur during "release to production". I'm thinking of just ignoring skills.json and just change it when I want to deploy. But I am also considering the ability to allow others to deploy it in their own machines.
Any suggestions on how should I approach this using ask-cli?

Using the API should allow you to control your source and target destinations however you like. Using "profiles" will allow you to keep separate sets of credentials also.
There are 2 different levels of control when using the ask-cli. One is high level, and simplifies creating, cloning, and updating skills. These use the format:
"ask new ..." or "ask clone" to create or copy an existing skill
"ask deploy ..." to update parts or all of the skill.
A lower level API is available that allows more specific control. These use the format "ask api ..." and allow you to specify for example the specific file to upload/download to/from. I've found these better for projects with staging, develop, testing branches, etc.
In all of the ask commands, you can provide a profile that specifies the credentials for the Alexa developer account and the AWS account for the Lambda. Use the "ask init" to set these up. I keep separate profiles for:
my home/hobby projects using my personal accounts
my work related development/debugging
my work client projects accessible by our testers and clients.
The Amazon doc is pretty well written, and explains how to use the ask-cli. It just doesn't go into why you would use multiple profiles, etc.
I hope this helps. Start with the Amazon ask-cli quick start then follow the links to the reference documentation.
One thing to be careful about is to make sure that you are using the latest ask-cli download. As of today it is 1.0.0-beta.4. You can use the "ask -v" command to display your installed version. There were problems with the deploy command in the earlier 1.0.0-beta.1 version.

Related

Alexa Skill Developers Reference-Based Catalog Management API

This doc says "With the Reference-Based Catalog Management API, you can create a custom slot type that references an external data source to get the slot type values. This API allows you to create and maintain a catalog of slot type values independent of your Alexa skill."
However as you dig into it, it doesn't provide some needed details on how to actually setup the catalog on an endpoint like s3.
While this resource was provided as an answer in this similar question, it actually refers to content catalogs (like music playlists), not the Reference-Based Catalog Management API, so I assume that was in error and it is not applicable.
So, for the Reference-Based Catalog Management API: The docs say it needs to be in JSON format, and offers ingredients.json as an example. However I used this directly, and it fails (see below). Also, it does not describe what the format should be to include synonyms. Please describe this.
I can successfully create the catalog with '/v1/skills/api/custom/interactionModel/catalogs/' and get a catalogId in return. However, creating the catalog version via '/skills/api/custom/interactionModel/catalogs/{catalogId}/versions' fails. I get "Website Temporarily Unavailable" when I issue the POST.
Here's the request body structure that I'm including with that post:
data: {
"source": {
"type": "URL",
"url": "https://s3.amazonaws.com/..../ingredients.json"
},
"description": "test S3 bucket"
}
Also, does the S3 endpoint have to be made public? I tried it both ways, didn't seem to matter. If it does have to be public though, how did you handle security?
Thanks for the help.
While the API call fails, I did get this to work using the CLI approach.
ask api create-model-catalog-version -c {catalogID} -f {filename}
The file should be JSON with the following structure:
{
"type": "URL",
"url": "[your catalog url]"
}
It remains an open question how to get the API approach to work, so any answers appreciated. Maybe it is a bug, because I specify the exact same 'source' definition in the data structure of the API call as I do in the JSON file used by the CLI command.
Here's what I learned as I got it to work with the CLI:
Yes, the S3 endpoint must be made public in order for the create-model-catalog-version job to succeed. This strikes me as a problem, would like to see the ability to wrap some security around these endpoints.
Here is the format of the JSON that you will want to use, including the use of synonyms which is not described in the official Amazon example. Note that you don't have to include an ID as shown in that example.
{
"values": [
{
"name": {
"value": "hair salon",
"synonyms": [
"hairdresser",
"beauty parlor"
]
}
},
{
"name": {
"value": "hospital",
"synonyms": [
"emergency room",
"clinic"
]
}
},
]
}

How to retrieve member list from Silverstripe API

I am developing a platform and I need to get the members emails from an existing Silverstripe installation. I think it is V4 but not sure yet.
I was hoping to call a REST API but I can't seem to find any information about how you would go about doing this. I would need to call this each day to get the latest members.
Is this possible or is there another way to go about doing this?
I had a look at the API documentation but the information is not helpful and it does not have an explanations or examples. https://api.silverstripe.org/4/index.html
Silverstripe 4 does not expose its data through a REST API service out of the box. We can install a module to allow us to do this.
Rest API module:
https://github.com/colymba/silverstripe-restfulapi
Rest API module:
https://github.com/silverstripe/silverstripe-restfulserver
An alternative is to use the Silverstripe GraphQL module to retrieve data:
https://github.com/silverstripe/silverstripe-graphql
You can do this almost out of the box with the SilverStripe GraphQL API in SilverStripe 4. In addition to 3dgoo's answer, here's a bit of a guide for you:
Out of the box configuration
SilverStripe exposes an "admin" GraphQL server, which requires you to be logged in to use it. If you want to use it from another server, you can base64 encode your basic authentication credentials and pass it as a header. More info on this here.
The SilverStripe CMS module already exposes member's first and last names, since they're used by parts of the CMS through the GraphQL API already. If you want an email address then you can add that with some basic YAML in your app folder.
Adding the member's email field
Add some custom configuration to your app/_config folder - configuration in SilverStripe is merged, so the array values fields: [Email] will merge with the CMS values linked above
# File: app/_config/graphql.yml
---
Name: appgraphql
---
SilverStripe\GraphQL\Manager:
schemas:
admin:
scaffolding:
types:
SilverStripe\Security\Member:
fields: [Email]
operations:
read: true
Note that I've also added operations.read: true to this, because the CMS will only let you read members one at a time via the readOne operation. For your case you'll want to enable read, which returns a paginated list. More info on available operations.
Testing your query
The easiest way to do this is to install GraphiQL (via silverstripe-graphql-devtools), a web (or app) based UI for inspecting GraphQL schemas and running queries against your server. This can be done easily with Composer:
composer require --dev silverstripe/graphql-devtools dev-master
Open up your browser to http://localhost/dev/graphiql?flush. Replace localhost with whatever your SilverStripe server is running on. You add ?flush to the querystring to tell SilverStripe to flush its cache (YAML and PHP files) to pick up your new module and config.
When you get your GraphiQL query editor you can start by writing query GetUsers { ... } and you'll notice that as you type deeper into the query it autocompletes the available options for you.
Here's the query to retrieve your member email addresses:
query GetUserEmails {
readSilverStripeMembers {
edges {
node {
Email
}
}
}
}
Micro-explanation: GetUserEmails is an arbitrary query name you create. You don't actually need to write one, it'll work fine without. readSilverStripeMembers is an automatically scaffolded query name, which happens because you enabled read: true in the GraphQL operations. If you delete it and start typing it again you'll see the other options available as well, the one that ships out of the box with the CMS is readOneSilverStripeMember. The edges and node levels are for pagination.
Using the query
It sounds to me like your SilverStripe server is already running somewhere, and you may not have a local version to test. If that's the case, simply adding the YAML configuration above to your app folder and deploying it will be enough to get your server to give member emails in admin GraphQL calls, then you can do your GraphQL queries with cURL or something:
curl 'http://localhost/admin/graphql/' \ # Adjust to your domain
-H 'Authorization: Basic YWRtaW46YWRtaW4=' \ # This is admin:admin base64 encoded
-H 'Content-Type: application/json' \ # Required for the input data structure
--data-binary '{"query":"query { readSilverStripeMembers { edges { node { Email } } } }","variables":null}'
Example output:
{
"data": {
"readSilverStripeMembers": {
"edges": [
{
"node": {
"Email": "leslie.lawless#example.com"
}
},
{
"node": {
"Email": "mika#example.com"
}
},
{
"node": {
"Email": "sam#example.com"
}
}
]
}
}
}

Zerocode: Set system property in host configuration file

Configuration:
zerocode-tdd.1.3.2
${host}
At runtime, system property set with -D java option. All is well.
Problem / What I Need:
At unit test time, system property not set, and host not resolved.
App uses Junit and Zerocode, would like to simply configure Zerocode to set the system property.
Example:
host.properties
web.application.endpoint.host:${host}
web.application.endpoint.port=
web.application.endpoint.context=
More Info:
Requirement is for configuration only. Can't introduce new Java code, or entries into IDE.
Any help out there? Any ideas are appreciated.
This feature is available in zerocode version 1.3.9 and higher.
Please use the place holder like ${SYSTEM.PROP:host} e.g. ${SYSTEM.PROPERTY:java.vendor} resolves to Oracle Corporation or Azul Systems, Inc.
Example link:
https://github.com/authorjapps/zerocode/blob/master/README.md#general-place-holders
Found a solution, but not sure if this is the correct way to do so.
Step 1: Create a config file and load system properties.
Config.java
public class Config {
public Map<String, Object> readProperties(String optionalString) {
Map<String, Object> propertiesMap = new HashMap<>();
final String host = System.getProperty("host");
propertiesMap.put("host", host);
return propertiesMap;
}
}
Step 2: Add a step (before other steps) to use the loaded properties in the .json file.
test.json
{
"scenarioName": "Test ...",
"steps": [
{
"name": "config",
"url": "com.test.Config",
"operation": "readProperties",
"request": "",
"assertions": {}
}
]
}
Step 3: Use loaded property in step config
test.json
{
"scenarioName": "Test ...",
"steps": [
{
"name": "config",
"url": "com.test.Config",
"operation": "readProperties",
"request": "",
"assertions": {}
},
{
"name": "test",
"url": "${$.config.response.host}/test/xxx",
"operation": "GET",
"request": {},
"assertions": {
"status": 200
}
}
]
}
That's it, although it is working but I am looking for better approach.
Some possible options I am trying are:
Common step for load/config (in one place)
Directly using properties as {host} in json files
Custom client
Again any help/ideas are appreciated.
My question is why are you trying to access the actual host/port? Sorry for the long answer but bear with me. I think there is an easier way to achieve what you are attempting. I find its best to think about zerocode usage in two ways,
live integration tests (which is what I think your trying to do) [meaning this calls a live endpoint / service], or
what I refer to as a thintegration test (an integration test but using a mock endpoint / service).
Thinking about it this way gives you the opportunity for two different metrics,
when using the mock endpoint / service how performant / resilient is my code, and
when using live integration tests what is the rough real life performance (expect a bit slower than external load test due to data setup / test setup).
This lets you evaluate both yourself and your partner service.
So outside of the evaluation above why would you want to build a thintegration test? The real value in doing this is you still make it all the way through your code like you would in an integration test but you control the result of said test like you would in a standard unit test. Additionally since you control the result of the test this may improve build time test stability vs a live api.
Obviously it seems you already know how to setup an integration test so I'll assume you're good to go there but what about the thintegration tests?
To setup a thintegration test you really have two options,
use postman mock server (https://learning.postman.com/docs/designing-and-developing-your-api/mocking-data/setting-up-mock/)
a. more work to setup
b. external config to maintain
c. monthly api call limits
use WireMock (http://wiremock.org/)
a. lives with your code
b. all local so no limits
If you already have integration tests you can copy them to a new file and make the updates or just convert your existing.
**** To address your specific question ****
When using WireMock you can setup a dynamic local server url with dynamic port using the following.
protected String urlWithPort;
#Rule
public WireMockRule wireMockRule = new WireMockRule(wireMockConfig().dynamicPort().dynamicHttpsPort());
protected String getUriWithPort() {
return "http://localhost:" + wireMockRule.port();
}
Note: The above was tested using WireMock version 2.27.1 and ZeroCode 1.3.27
Hope that helps you answer how to dynamically get a server/port for your tests.

Using Azure Quickstart Templates on Azure Government

I'm attempting to use the 3 VM SharePoint Azure QuickStart Template on Azure Government.
Everything works fine except that the deployment errors out due to the fact that Azure Government expects the storageAccountUri to be blob.core.usgovcloudapi.net, while the default is blob.core.windows.net.
I've changed the JSON files to the expected blob.core.usgovcloudapi.net, but it still complains of the error that the blob URL's domain must be blob.core.usgovcloudapi.net.
I'm wondering why it is being overridden and how I can prevent that.
An example of the change I've made is:
"osDisk": {
"name": "osdisk",
"vhd": {
"uri": "[concat('http://',parameters('storageAccountNamePrefix'),'1.blob.core.usgovcloudapi.net/vhds/',parameters('sqlVMName'),'-osdisk.vhd')]"
},
"caching": "ReadWrite",
"createOption": "FromImage"
Any help would be appreciated.
You should be able to reference the storage account and that will ensure you always get the correct address (regardless of cloud):
"osDisk": {"name": "osdisk","vhd": {"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/',
variables('storageAccountName')), '2015-06-15').primaryEndpoints.blob, variables('vmStorageAccountContainerName'), '/',variables('OSDiskName'),'.vhd')]"}}
We have some other tips for using a QuickStart that might be hard coded to a single cloud here:
https://blogs.msdn.microsoft.com/azuregov/2016/12/02/azure-quickstart-templates/

Apple App Site association not working

App Search API Validation Tool of "Apple" is not validating my domain.
https://search.developer.apple.com/appsearch-validation-tool
I am using universal links but "Link to Application" is showing me "Error".(http://www.awesomescreenshot.com/image/1719847/330979a43c4c6b2766da1e703447ee04)
Here is my "apple-app-site-association" file code.
{"applinks": {"apps": [],"details": {"XXXXXXXXXX.com.streatmanagement.threadshare": {"paths": ["*"]}}}}
Can someone please solve my query or send the sample of "apple-app-site-association" valid code?
Apple's API validation tool compares your website's association file to a store listing. If your app is not yet publicly available the error you listed will be displayed.
Your apple-app-site-association has a small typo where you specify the details (it should be an array). I also assume you're replacing the XXXX's with your app ID.
{
"applinks": {
"apps": [],
"details": [
{
"appID": "APPID.BUNDLEID",
"paths": [ "*" ]
}
]
}
}
Even if you get this error from Apple's validation tool, you can test Universal links. If your Universal Link does not work on your test device you need to inspect the device logs when you fresh install it and make sure your apple-app-site-association is available at the root of your site via https with no redirects. Sometimes there is issue if the content-type is not application/json (but the file name should remain exactly apple-app-site-association).

Resources