Skip to content

Latest commit

 

History

History
225 lines (149 loc) · 12.5 KB

File metadata and controls

225 lines (149 loc) · 12.5 KB

Contributing to Functionless

Thank you for your interest and contribution in Functionless.

Getting Started

Requirements:

  • Node 14+
  • Yarn
  • Docker
    • Used in the tests. Docker daemon must be running.
  • Localstack
    • Used in the tests.

Fork the repo and then run:

$ git clone https://github.com/{your-account}/functionless.git
$ cd functionless
$ yarn install

We do all of our work in VSCode and include configuration files to improve the developer experience. There is no strict dependency. Suggested plugins: vscode-jest, prettier-vscode, streetsidesoftware.code-spell-checker.

Layout

  • / and /src - The Functionless Package - containing compiler (src/compiler.ts), transpilers (src/vtl.ts), and publicly exposed resources (Function, StepFunction, etc). Generates the functionless NPM repo.
  • /test - Tests for the main repo, see testing
  • /website - Functionless.org code
  • /test-app - A series of test CDK applications which consume functionless via npm. We use this to test compilation of various "real world" scenarios and CDK synthesis.

Functionless leverages the typescript compiler api. compile.ts runs over the ts of a consuming application, validating, transforming, and extracting necessary information.

Note: Functionless does not compile itself, at the moment, functions like reflect cannot be used to transform the core functionless source. /tests are compiled.

The compiler outputs the functionless AST (/src/expression.ts, /src/declaration.ts, /src/statement.ts) into the transpiled javascript which is used by the resources (/src/function.ts, /src/step-function.ts, etc) during cdk synthesis to infer infrastructure (CDK Constructs) and transpile typescript/Functionless AST to cloud native languages (ASL, Velocity).

Building Functionless

$ yarn install
$ yarn watch

Guidelines

  • Every change or bug fix MUST come with one or more tests that would break before the change.
  • Errors MUST be documented as Error Codes with detailed descriptions.
  • Errors SHOULD be discovered via /src/validate.ts. /src/validate.ts runs with the functionless cli and the @functionless/language-service in the IDE to give early errors to consumers.
  • No/Minimal Magic - Core Functionless resources should improve the developer experience without introducing opinionated implementation. The goal is to translate typescript behavior into AWS services. The infrastructure created should be clear and logical. For example, Step Functions cannot perform arithmetic natively, we will not automatically create/call a lambda to do it. We will validate for arithmetic, throw an error, and show how a Function can be used as a workaround. We may introduce higher level constructs or integrations that accomplish the "magic" behavior.

Testing

Required:

  • Docker
    • With the docker daemon running.
  • Localstack

Commands:

  • yarn test - boots up localstack, runs all tests, stops localstack
  • yarn test:fast - runs all non-localstack tests
  • yarn test:update - runs all tests and updates snapshots
  • yarn test:watch - watches for changes to the source and re-runs the tests.

Suggested: VSCode jest plugin - use the VSCode jest plugin to run individual tests and debug.

When using any method that does not invoke yarn test, ./script/localstack may be used to start localstack (and boostrap CDK) manually.

Testing compiler changes

The compiler transforms the consumer's typescript. This output can be seen by looking at the Javascript files output by Typescript. By default, jest caches this output, which means your compiler changes may not apply to the next test run. If making changes to the compiler, you'll want to either make changes to your test source to force the cache to refresh, explicitly clear the jest cache npx jest --clearCache, or run without the cache npx jest --cache false.

Compiler code can be debugged, however, ensure that jest actually runs the compiler by using one of the cache clearing mechanisms above. When testing the compiler, all of the uncached typescript files will be processed, making it difficult to debug specific tests. One strategy is to isolate your test in it's own file temporarily and continually make small changes (like updating the name), to break the cache.

Another option to test compiler changes is using the includes VSCode Launch Configuration compile test-app. This will explicitly compile the /test-app and supports the debugger.

Test App

$ cd test-app
test-app$ yarn install
test-app$ yarn watch

Test Options

Env Description
TEST_DEPLOY_TARGET Deploy to AWS (with default credential chain) or LOCALSTACK, Default: LOCALSTACK
TEST_STACK_RETENTION_POLICY After tests complete, RETAIN, DELETE, or SELF_DESTRUCT (delete after TEST_SELF_DESTRUCT_DELAY_SECONDS). Default: SELF_DESTRUCT
TEST_SELF_DESTRUCT_DELAY_SECONDS Number of seconds to wait before self destructing the stack, Default: 12 hours (43200s)
CLEAN_UP_STACK Deploys a CFN stack that can delete all of the test stacks (and itself) when invoked. Used the in Pull Request Closed CleanUp workflow to clean up after PRs.

Website

The doc site contains marketing, documentation, and blogs on Functionless.org. It is built using Docusaurus v2.

  • /website/docs/api/* - Auto generated by typedocs. Generation happens on yarn start or via netlify when a PR is pushed.
  • /website/docs/error-codes.md - Auto generated by typedocs and the /scripts/compile-error-code-page.js script. Generation happens on yarn start or via netlify when a PR is pushed.
  • /website/docs/concepts - Hand written documentation for functionless resources. Update as needed.

To watch during development:

$ cd website
website$ yarn start

To simulate the netlify build, run (at the root directory)

$ yarn build:website

Additions

Error Codes

Functionless maintains well documented and linked error codes for compiler and synth errors.

  • Compiler Errors - Errors in the source discovered during the compile/transform phase.
    • Note: the compiler should never throw all of the way up the stack. Use the errorBoundary method to catch errors and turn them into Err AST nodes. Err nodes should be checked for when transpiling where they can be re-thrown.
    • The validator (/src/validate.ts) and language service (@functionless/language-service) should be used to expose compile time errors to the consumer.
  • Synth Errors - Errors encountered while generating the infrastructure in CDK Synth.

Error Code Strategy

#182 (comment)

TLDR; keep it simple and follow Typescript/React

  1. Error Codes - Start at 10000
  2. Error Message/Title
  3. Type - Error, Warning, Info, Deprecated

All errors should be functionless(code) - If the error pertains to a specific service, the message should include that. If an error code is no longer relevant, we do not re-use the code, change the type to deprecated and stop returning the error. At major version bumps, we will clean up the deprecated errors and re-evaluate.

Add a new Error Code

  1. Add a new exported constant in the src/error_codes.ts file.
/**
 * Error thrown when doing something bad.
 * ```ts
 * some code showing valid and invalid cases
 * ```
 *
 * ### More context
 *
 * This is why this error happens, tickets that may resolve the issue, context links, aws/cloud/cdk limitations.
 *
 * ### Workaround
 *
 * As an alternative, do this
 *
 * ```ts
 * // something that achieves the behavior or close to it
 * ```
 **/
export const My_New_Error: ErrorCode {
	type: ErrorType.ERROR,
	title: "my new error",
	code: 19999
}

type -

  • ERROR - Should fail validation, cli. An error signifies that consumer logic will fail or during compile, synth, or runtime, generally due to an explicit error from Functionless.
  • WARN - Should show warning during validation, cli. A warning signifies that consumer logic MAY fail or act in undefined ways during compile, synth, or runtime
  • INFO - Show info during validate. Will not fail during compile, synth, or runtime.
  • DEPRECATED - Errors or warnings that are no longer applicable. (We unblocked the use case, for example).

Title - A short, single sentence with no punctuation describing what the error is. The title of the error on the Error Code page. The anchor created on the url. The message text printed by default with a SynthError.

Code - Unique, numeric code, starting at 10000. Will be displayed in the IDE and website to uniquely identify the error even if the message text changes.

TSDocs - Above the ErrorCode, TS docs should be used to describe the error in detail. This can contain markdown, which will be turned into markdown in the docs. Include code examples of what not to do is possible, go into detail on the issue, and explain any workarounds or escape hatching available to bypass the issue.

  1. [Optional] - Add validation

Any ErrorCode which can be determined statically should have static validation added to validate.ts. validate.ts uses the Typescript AST to find errors which would be thrown later. validate.ts is used by the functionless api (npx functionless) and the @functionless/language-service.

If the error code cannot be validated, add the new error code to skipErrorCodes in validate.test.ts. You must explain why validation cannot be added in the PR and comments.

  1. [Optional] - Add a validation test

If step 2 created validation, add an error code to the corresponding test/test-files file(s) and run the tests to recreate the snapshot. The snapshot should show new errors for each test case added.

In the rare case that validation is added, but cannot be re-created in the test/test-files, add the new error code to skipErrorCodes in validate.test.ts. You must explain why validation cannot be added in the PR and comments.

PR

Create a PR from your fork to functionless main.

Review Conventional Commits for details on how to submit a pull request.

Title: feat/fix/chore(feature): lower case concise description Title Example: feat(lambda): support event sources

Feature names are optional and should come from the repo labels.

Breaking Changes:

Breaking changes will force a version bump (major version bump after version 1.0).

To declare a breaking change add:

BREAKING_CHANGE: ...

To the bottom of your PR description. When we merge the PR into main, the BREAKING_CHANGE will be retained in the squash commit message.

Note: PRs should not use force pushes, always push new commits to the PR branch, including periodic merges from live as main is updated.

Troubleshooting

Function Not Compiled

[Error 10001 - Function not compiled]https://functionless.org/docs/error-codes#function-not-compiled-by-functionless-plugin

The SWC plugin isn't running on your code. See the Getting Started documentation for steps on how to properly configure SWC.