question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

RFC: Runtime Hooks

See original GitHub issue

This is a Request For Comments (RFC). RFCs are intended to elicit feedback regarding a proposed change to the Amplify Framework. Please feel free to post comments or questions here.

Summary

There is a need to perform automations or tasks during lifecycle events of Amplify CLI commands. Runtime hooks help customers run custom scripts during Amplify CLI’s lifecycle events. Customers can hook into a lifecycle event by adding their script files to the hooks directory. Amplify CLI detects and executes the corresponding script during the lifecycle event.

Common Runtime Hooks Use Cases

Security checks

Customers can write scripts to scan for sensitive information before push or publish events. If there is a detected vulnerability, customer scripts can stop the execution of Amplify CLI command by exiting with a non zero code. Example of running credential scanner before push:

if keychecker --path $projectRoot; then
    # no vulneribility found
    exit 0
else
    echo "found security vulneribility"
    exit 1
fi

Running local tests

Customers can write hook scripts to run preexisting test suits. Following is an example of bash script running npm test:

# running npm tests in pre-push script
npm test
testPassed=$?
if [ $testPassed -eq 0 ]; then
    echo "npm tests passed"
    exit 0
else
    echo "npm tests failed"
    exit 1
fi

To maintain execution consistency, especially within cross-teams, customers can use runtime hooks to test for Amplify CLI version and halt Amplify CLI commands execution if inconsistent version is present.

const process = require("process");
const data = JSON.parse(process.argv[2]);
const teamAmplifyVersion = "4.52.0";
if (teamAmplifyVersion != data.amplify.version) {
  process.exit(1);
}

Hook scripts can also run linters and code formatters to ensure that codebase follows lint and format rules.

Logging and notifications for Amplify CLI events

Using hooks, customers can send email or slack messages or store logs. Customers will be able to utilize runtime parameters in their scripts to create detailed logs.

const axios = require("axios");
const process = require("process");
axios
  .post(
    "https://slack.com/api/chat.postMessage",
    {
      channel: "Amplify",
      text:
        "Amplify push was successfully executed!",
    },
    { headers: { authorization: `Bearer ${"SLACK_API_TOKEN"}` } }
  )
  .then((res) => {})
  .catch((err) => {});

Customer Workflow

  • Amplify CLI generates a hooks directory in amplify/backend with sample hook scripts on amplify init. For existing projects, this folder and sample scripts will be created on amplify upgrade.
  • Customers will add scripts in hooks directory following the naming convention to hook into a specific lifecycle event.
  • Amplify CLI will execute the hook scripts synchronously during the corresponding event and log scripts’ errors and messages to the shell.

All the scripts in the hooks directory will be git committed by default which is different from git hooks. To support cross platform compatibility, Amplify hook scripts are not executable files.

New Amplify CLI generated directory structure after amplify init:

 -amplify
   -backend
      -hooks // all hooks scripts go within this directory
        -pre-push.js.sample
        -post-push.sh.sample

Naming convention:

Files in the hooks directory should follow the format pre|post-<command>[-<sub-commmand>].extension. sub-commmand is optional and can be used to increase hook specificity. Example: pre-add-auth and pre-mock-api. If there are pre-add.js, pre-add-auth.js, post-add.js and post-add-auth.js scripts present, Amplify CLI will execute in the following order: pre-add.js > pre-add-auth.js > amplify add auth > post-add-auth.js > post-add.js

Scripting Languages and Supported Lifecycle events:

Amplify CLI will support bash(.sh) and node(.js) scripts. All scripts are auto-detected based on the extension. If there are files present with same filename and different extensions, extension with naming precedence will be executed. For customers or teams using cross platform operating system, it is recommend to use javascript over bash.

Amplify CLI will support pre and post lifecycle events for the following amplify commands and sub-commands:

  • add
  • update
  • remove
  • push
  • status
  • delete
  • pull
  • publish
  • mock
  • env
  • codegen
  • gql-compile

Parameters passed to Hook Scripts

When a lifecycle event is called, Amplify CLI passes runtime parameters into hook scripts as command line arguments. There are two JSON strings that will be passed as parameters to hook scripts: data and error. The sample scripts generated by amplify init will have boilerplate template to showcase parsing and using these parameters. Following describes the structure of the two parameters:

data: JSON string with the following structure:

{
     projectPath: String,
     amplify: { 
          version: String,
          environment: String,
          command: String,
          subCommands: [ String ],
          options: { String: Boolean|String }
     }
}
  • projectPath - path to root directory of customer’s amplify project
  • amplify -
    • version - current Amplify version
    • environment - current Amplify environment
    • command - Amplify CLI command executed. Example: push
    • subCommands - list of Amplify CLI subcommands or plugins executed. Example auth, storage
    • options - JSON object containing command line option passed as key and either a boolean or a string as value. Example: For amplify push --yes, the options object would be { yes: true }.

error: JSON string in case Amplify CLI emits an error, null otherwise. It has the following structure:

{
     "message": String,
     "stack": String
}
  • message: the error message emitted by Amplify CLI
  • stack: the error stack emitted by Amplify CLI

Exit status

To stop the execution of Amplify CLI, the hook script can exit with a non-zero status and Amplify CLI will generate necessary logs and gracefully exit.

Third party packages and Amplify Console support

Customers can use third party packages in hook scripts given those packages are imported correctly and are accessible during execution. For instance, if a pre-push script uses jest to run tests, customers should run npm i -g jest or npm i jest once before Amplify CLI executes the pre-push script.

Amplify Console is automatically supported and hook scripts will be executed by the console similar to the execution on local machine.

Customers can use third party dependency and Amplify Console simultaneously by modifying amplify.yml file to install dependency packages (backend preBuild). More information about running preBuild commands in console can be found in the Amplify docs. Example amplify.yml file snippet to install jest:

version: 1
env:
  variables:
      key: value
backend:
  phases:
    preBuild:
      commands:
        -npm install jest -g
    build:
      commands:
        -amplifyPush --simple

Appendix

Sample generated scripts

pre-add.js.sample and post-add.sh.sample are sample scripts created on amplify init in the hooks directory.

pre-add.js.sample

// This is a sample script created by Amplify CLI.
// To start using this script please change the filename:
// pre-add.js.sample  ->  pre-add.js
//
// parameters available:
// process.argv[0] - path to node executable (default)
// process.argv[1] - path to the running script file (default)
// process.argv[2] - data - String JSON argument (passed by Amplify)
// process.argv[3] - error - String JSON argument or null (passed by Amplify)
//
// exiting with a non zero status - process.exit(1)
// will result in Amplify CLI process to exit.

const process = require("process");

const error = JSON.parse(process.argv[3]);
if (error !== null) {
  console.log("Amplify CLI emitted an error:", error.message);
  process.exit(1);
}

const data = JSON.parse(process.argv[2]);
console.log("project root path:", data.projectPath);
console.log("Amplify CLI command:", data.amplify.command);
console.log("Amplify CLI sub-commands:", data.amplify.subCommands);

process.exit(0);

post-add.sh.sample

# This is a sample script created by Amplify CLI.
# To start using this script please change the filename:
# post-add.sh.sample  ->  post-add.sh
#
# parameters available:
# $0 - path to the running script file (default)
# $1 - data - String JSON argument (passed by Amplify)
# $2 - error - String JSON argument or null (passed by Amplify)
#
# exiting with a non zero status - exit 1
# will result in Amplify CLI process to exit.

if [ -z "$(which jq)" ]; then
    echo "Please install jq to run the sample script."
    exit 1
fi

if ! [ -z "$2" ]; then
    echo "Amplify CLI emitted an error:" $(echo $2 | jq -r '.message')
    exit 1
fi

projectPath=$(echo $1 | jq -r '.projectPath')
amplifyCommand=$(echo $1 | jq -r '.amplify | .command')
amplifySubCommands=$(echo $1 | jq -r '.amplify | .subCommands | .[]')
echo "project root path:" $projectPath
echo "Amplify CLI command:" $amplifyCommand
echo "Amplify CLI sub-commands:" $amplifySubCommands

exit 0

Questions for the community

  • How and which particular use case(s) would be helpful to you? Are there any use cases that are missing here that Amplify team should consider?
  • Which lifecycle event(s) would be most useful for you (Ex.: pre-push, post-push, pre-add-auth, etc)?
  • Which values would be useful to be passed as parameters to the hook scripts?
  • Which language would you prefer to use for writing hook scripts?

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:27
  • Comments:9 (4 by maintainers)

github_iconTop GitHub Comments

3reactions
cmaycumbercommented, Jun 25, 2021

This is awesome.

How and which particular use case(s) would be helpful to you? Are there any use cases that are missing here that Amplify team should consider?

Which lifecycle event(s) would be most useful for you (Ex.: pre-push, post-push, pre-add-auth, etc)?

I would instantly use the following lifecycles off the top of my head:

  • pre-push (Compile a custom typescript function into js inside of the function/src folder using esbuild)
  • post-add-function (Create a custom function that uses typescript)
  • pre-add-auth (Make sure that my custom user pool, deployed through AWS CDK, is up and running for that particular stage)

Which values would be useful to be passed as parameters to the hook scripts?

Maybe certain configurations for functions? e.i For my use case outlined above, a function-type param, for example --trigger-type=cognito-trigger creates a typescript function that already has the types for UserPoolTriggers.

Which language would you prefer to use for writing hook scripts?

Bash and Node.js

Another reason I think this RFC is so great is that I think it adds a large amount of flexibility to Amplify which I’ve found in the past to be limiting.

0reactions
github-actions[bot]commented, Dec 10, 2021

This issue has been automatically locked since there hasn’t been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels for those types of questions.

Read more comments on GitHub >

github_iconTop Results From Across the Web

[pre-RFC] Additional Target Hooks - Apache TVM Discuss
In order to enable flexibility in how individual targets are lowered and built within TVM, this RFC proposes supporting additional hooks on ...
Read more >
Vue maintainers proposed, listened, and revised the RFC for ...
Inspired by React Hooks, its objective is to provide developers a “clean and flexible way” to compose logic and share it between components....
Read more >
[RFC PATCH v3 0/3] Safe, dynamically loadable LSM hooks
[RFC PATCH v3 2/3] security: Expose a mechanism to load lsm hooks dynamically at runtime 2018-02-20 2:13 [RFC PATCH v3 0/3] Safe, dynamically...
Read more >
Alex Lobera on Twitter: "RFC to consider two new React hooks for ...
RFC to consider two new React hooks for LeanJS runtime. Do you want share your opinion? github.com. chore(rfc): new React hooks to share...
Read more >
[Pre-RFC] `libstd` hooks - libs - Rust Internals
These libstd hooks would make it possible for libstd to be completely independent of the underlying runtime environment and would allow ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found