Thanks for taking the time to help improve the AWS Toolkit! We greatly value feedback and contributions from the community.
Reviewing this document will maximize your success in working with the codebase and sending pull requests.
If you're looking for ideas about where to contribute, consider good first issue issues.
To develop this project, install these dependencies:
- Visual Studio Code
- NodeJS and NPM (latest version of both)
- Typescript
- Git
- (optional) Set
git blame
to ignore noise-commits:git config blame.ignoreRevsFile .git-blame-ignore-revs
- (optional) Set
- AWS
git secrets
- (optional) AWS SAM CLI
- (optional) Docker
Then clone the repository and install NPM packages:
git clone [email protected]:aws/aws-toolkit-vscode.git
cd aws-toolkit-vscode
npm install
You can run the extension from Visual Studio Code:
- Select the Run panel from the sidebar.
- From the dropdown at the top of the Run pane, choose
Extension
. - Press
F5
to launch a new instance of Visual Studio Code with the extension installed and the debugger attached.
When you launch the extension or run tests from Visual Studio Code, it will automatically build the extension and watch for changes.
You can also use these NPM tasks (see npm run
for the full list):
- To build once:
npm run compile
- To build and watch for file changes:
npm run watch
- To build a release artifact (VSIX):
npm run package
- This uses webpack which may exhaust the default Node heap size on Linux.
To fix this set
--max-old-space-size
:export NODE_OPTIONS=--max-old-space-size=8192
- This uses webpack which may exhaust the default Node heap size on Linux.
To fix this set
- To build a "debug" VSIX artifact (faster and does not minify):
npm run package -- --debug
- Project patterns and practices: CODE_GUIDELINES.md
- VS Code Extension Guidelines
- VS Code API Documentation
- VS Code Extension Capabilities
-
VSCode extensions have a 100MB file size limit.
-
src/testFixtures/
is excluded in.vscode/settings.json
, to prevent VSCode from treating its files as project files. -
The codebase provides globals, which must be used instead of some common javascript globals. In particular, clock-related things like
Date
andsetTimeout
must not be used directly, instead useglobals.clock.Date
andglobals.clock.setTimeout
. #2343 -
VSCode extension examples: https://github.com/microsoft/vscode-extension-samples
-
Tests
- Use
function ()
andasync function ()
syntax fordescribe()
andit()
callbacks instead of arrow functions. - Do NOT include any
await
functions indescribe()
blocks directly (usage inbefore
,beforeEach
,after
,afterEach
, andit
blocks is fine).await
indescribe()
causes the framework to always evaluate thedescribe
block and can cause issues with either tests not running or always running (if other tests are marked with.only
)- Tests that require a premade value from a Promise should initialize the value as a
let
and make theawait
ed assignment inbefore()
.
- Use
-
How to debug unresolved promise rejections:
- Declare a global unhandledRejection handler.
process.on('unhandledRejection', e => { getLogger('channel').error( localize( 'AWS.channel.aws.toolkit.activation.error', 'Error Activating {0} Toolkit: {1}', getIdeProperties().company, (e as Error).message ) ) if (e !== undefined) { throw e } })
- Put a breakpoint on it.
- Run all tests.
- Declare a global unhandledRejection handler.
See TESTPLAN.md to understand the project's test structure, mechanics and philosophy.
You can run tests directly from Visual Studio Code:
- Select
View > Debug
, or select the Debug pane from the sidebar. - From the dropdown at the top of the Debug pane, select the
Extension Tests
configuration. - Press
F5
to run tests with the debugger attached.
You can also run tests from the command line:
npm run test
npm run integrationTest
Tests will write logs to ./.test-reports/testLog.log
.
To run a single test in VSCode, do any one of:
-
Run the Extension Tests (current file) launch-config.
-
Use Mocha's it.only() or
describe.only()
. -
Run in your terminal:
- Unix/macOS/POSIX shell:
TEST_FILE=src/test/foo.test npm run test
- Powershell:
$Env:TEST_FILE = "src/test/foo.test"; npm run test
- Unix/macOS/POSIX shell:
-
To run all tests in a particular subdirectory, you can edit
src/test/index.ts:rootTestsPath
to point to a subdirectory:rootTestsPath: __dirname + '/shared/sam/debugger/'
You can find the coverage report at ./coverage/index.html
after running the tests. Tests ran from the workspace launch config won't generate a coverage report automatically because it can break file watching. A few manual steps are needed instead:
- Run the command
Tasks: Run Build Task
if not already active - Instrument built code with
npm run instrument
- Exercise the code (
Extension Tests
,Integration Tests
, etc.) - Generate a report with
npm run report
You can find documentation to create VSCode IDE settings for CodeCatalyst blueprints at docs/vscode-config.md.
Before sending a pull request:
- Check that you are working against the latest source on the
master
branch. - Check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.
- Open an issue to discuss any significant work.
To send a pull request:
- Fork the repository.
- Modify the source; focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change.
- Read the project guidelines, this is very important for non-trivial changes.
- Commit to your fork using clear commit messages.
- Update the changelog by running
npm run newChange
.- Note: the main purpose of the
newChange
task is to avoid merge conflicts.
- Note: the main purpose of the
- Create a pull request.
- Pay attention to any CI failures reported in the pull request.
Generally your PR description should be a copy-paste of your commit message(s). If your PR description provides insight and context, that also should exist in the commit message. Source control (Git) is our source-of-truth, not GitHub.
Follow these commit message guidelines:
-
Subject: single line up to 50-72 characters
- Imperative voice ("Fix bug", not "Fixed"/"Fixes"/"Fixing").
-
Body: for non-trivial or uncommon changes, explain your motivation for the change and contrast your implementation with previous behavior.
- Often you can save a lot of words by using this simple template:
Problem: … Solution: …
- Often you can save a lot of words by using this simple template:
A good commit message has a short subject line and unlimited detail in the body. Good explanations are acts of creativity. The "tiny subject line" constraint reminds you to clarify the essence of the commit, and makes the log easy for humans to scan. The commit log is an artifact that will outlive most code.
Prefix the subject with type(topic):
(conventional
commits format): this again helps humans
(and scripts) scan and omit ranges of the history at a glance.
Each commit and pull request is processed by an automated system which runs all tests and provides the build result via the Details link as shown below.
Besides the typical develop/test/run cycle describe above, there are some tools for special cases such as build tasks, generating telemetry, generating SDKs, etc.
The DevSettngs class defines various developer-only settings that change the behavior of the
Toolkit for testing and development purposes. To use a setting just add it to
your settings.json
. At runtime, if the Toolkit reads any of these settings,
the "AWS" statusbar item will change its color. Use the setting aws.dev.forceDevMode
to trigger this effect on start-up.
The aws.dev.logfile
setting allows you to set the path of the logfile. This makes it easy to
follow and filter the logfile using shell tools like tail
and grep
. For example in
settings.json,
"aws.dev.logfile": "~/awstoolkit.log",
then following the log with:
tail -F ~/awstoolkit.log
Endpoint overrides can be set per-service using the aws.dev.endpoints
settings. This is a JSON object where each key is the service ID (case-insensitive) and each value is the endpoint. Refer to the SDK API models to find relevant service IDs.
Example:
"aws.dev.endpoints": {
"s3": "http://example.com"
}
Metrics are only emitted if the extension is assumed to be ran from an actual user rather than automation scripts.
This condition is checked through an environment variable AWS_TOOLKIT_AUTOMATION
which is set by test entry points.
If any truthy value is present, telemetry will be dropped if the current build is not a release version. Utility functions,
such as assertTelemetry
, can be used to test specific telemetry emits even in automation.
See docs/cfn-schema-support.md for how to fix
and improve the JSON schema that provides auto-completion and syntax checking
of SAM and CloudFormation template.yaml
files.
When the AWS SDK does not (yet) support a service but you have an API
model file (*.api.json
), use generateServiceClient.ts
to generate
a TypeScript *.d.ts
file and pass that to the AWS JS SDK to create
requests just from the model/types.
-
Add an entry to the list in
generateServiceClient.ts
:diff --git a/src/scripts/build/generateServiceClient.ts b/src/scripts/build/generateServiceClient.ts index 8bb278972d29..6c6914ec8812 100644 --- a/src/scripts/build/generateServiceClient.ts +++ b/src/scripts/build/generateServiceClient.ts @@ -199,6 +199,10 @@ ${fileContents} ;(async () => { const serviceClientDefinitions: ServiceClientDefinition[] = [ + { + serviceJsonPath: 'src/shared/foo.api.json', + serviceName: 'ClientFoo' + }, { serviceJsonPath: 'src/shared/telemetry/service-2.json', serviceName: 'ClientTelemetry',
-
Run the script:
npm run generateClients
-
The script produces a
*.d.ts
file (used only for IDE code-completion, not required to actually make requests):src/shared/foo.d.ts
-
To make requests with the SDK, pass the
*.api.json
service model toglobals.sdkClientBuilder.createAndConfigureServiceClient
as a genericService
withapiConfig=require('foo.api.json')
.// Import the `*.d.ts` file for code-completion convenience. import * as ClientFoo from '../shared/clientfoo' // The AWS JS SDK uses this to dynamically build service requests. import apiConfig = require('../shared/foo.api.json') ... const c = await globals.sdkClientBuilder.createAwsService( opts => new Service(opts), { apiConfig: apiConfig, region: 'us-west-2', credentials: credentials, correctClockSkew: true, endpoint: 'foo-beta.aws.dev', }) as ClientFoo const req = c.getThing({ id: 'asdf' }) req.send(function (err, data) { ... });
Webviews can be hot-reloaded (updated without restarting the extension) by running a developer server provided by webpack. This server is started automatically when running the Extension
launch configuration. You can also start it by running npm serve
. Note that only frontend components will be updated; if you change backend code you will still need to restart the development extension.
For extensions to contribute their own codicons, VS Code requires a font file as well as how that font maps to codicon IDs. The mapping is found in package.json
under the icons
contribution point. Icons located in resources/icons
are stitched together at build-time into a single font, automatically adding mappings to package.json
. More information can be found here.
As a simple example, let's say I wanted to add a new icon for CloudWatch log streams. I would do the following:
-
Place the icon in
resources/icons/aws/cloudwatch
. I'l name the iconlog-stream.svg
. -
Use
npm run generatePackage
to updatepackage.json
. Commit this change with the new icon. -
You can now use the icon in the Toolkit:
getIcon('aws-cloudwatch-log-stream')
The Toolkit codebase contains logic in src/dev/beta.ts
to support development during private betas. Creating a beta artifact requires a stable URL to source Toolkit builds from. This URL should be added to src/dev/config.ts
. Subsequent Toolkit artifacts will have their version set to 1.999.0
with a commit hash. Builds will automatically query the URL to check for a new build once a day and on every reload.
The marketplace page
is defined in README.quickstart.vscode.md
(which replaces README.md
during
the release automation). The vsce
package tool always replaces relative image paths
with URLs pointing to HEAD
on GitHub (https://github.com/aws/aws-toolkit-vscode/raw/HEAD/…/foo.gif
).
Note therefore:
- Don't delete images from
docs/marketplace/
unless the current published AWS Toolkit release doesn't depend on them. HEAD
implies that the URL depends on the current default branch (i.e.master
). Changes to other branches won't affect the marketplace page.
If you are contribuing visual assets from other open source repos, the source repo must have a compatible license (such as MIT), and we need to document the source of the images. Follow these steps:
-
Use a separate location in this repo for every repo/organization where images are sourced from. See
resources/icons/vscode
as an example. -
Copy the source repo's licence into this destination location's LICENSE.txt file
-
Create a README.md in the destination location, and type in a copyright attribution:
The AWS Toolkit for VS Code includes the following third-party software/licensing: Icons contained in this folder and subfolders are from <SOURCE_REPO_NAME>: <SOURCE_REPO_URL> <PASTE_SOURCE_LICENSE_HERE>
-
Add an entry here summarizing the new destination location, where the assets were sourced from, and a brief rationale.
PR #227 shows an example.
This project has adopted the Amazon Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.
If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via the vulnerability reporting page. Please do not create a public issue.
See the LICENSE file for our project's licensing. We will ask you to confirm the licensing of your contribution.
We may ask you to sign a Contributor License Agreement (CLA) for larger changes.