export const meta = { title: `Command Hooks`, description: `Execute custom scripts before, during, and after Amplify CLI commands (“amplify push”, “amplify api gql-compile”, and more).`, }; Use Command Hooks to execute custom scripts before, during, and after Amplify CLI commands (“amplify push”, “amplify api gql-compile”, and more). This allows you to extend Amplify’s best-practice defaults to meet your organization’s specific security guidelines and operational requirements. ## Adding a command hook Hooks need to be checked into source control in order to be made available across machines. `amplify pull` will not re-create the hooks folder automatically as these are considered changes that need to be committed to the repository. Place your custom scripts in the `amplify/hooks` directory and set the script file name to the desired command with a pre or post designation. For example `post-add-function.js` will execute the script after `amplify add function`. For more information about the script naming convention, see [How to name command hook scripts](#how-to-name-command-hook-scripts). For this example, let's create a hook to ensure that a minimum major Amplify CLI version is used before deployment (`amplify push`). Let's add `pre-push.js` in the `amplify/hooks` directory with the following contents. *Note: You need to create a `amplify/hooks` folder if your Amplify project was created prior to Amplify CLI version 5.5.0* ```js const fs = require('fs'); const parameters = JSON.parse(fs.readFileSync(0, { encoding: 'utf8' })); // Get the running Amplify CLI major version number const currentCLIMajorVersion = parameters.data.amplify.version.split('.')[0] console.log('Amplify CLI major version: ', currentCLIMajorVersion) const MINIMUM_MAJOR_AMPLIFY_CLI_VERSION = 5 console.log('Minimum required Amplify CLI major version: ', MINIMUM_MAJOR_AMPLIFY_CLI_VERSION) if (currentCLIMajorVersion < MINIMUM_MAJOR_AMPLIFY_CLI_VERSION) { // Non-zero exit code will stop the Amplify CLI command's execution console.log('Minimum CLI version requirement not met.') process.exit(1) } else { console.log('Minimum CLI version requirement met.') process.exit(0) } ``` Next, let's run `amplify push`: ```bash amplify push ``` ```console ----- 🪝 pre-push execution start ----- Amplify CLI major version: 5 Minimum required Amplify CLI major version: 5 Minimum CLI version requirement met. ----- 🪝 pre-push execution end ----- ``` ## How to name command hook scripts To hook into a command, the script file in the `amplify/hooks` directory should be named with the following naming convention: `pre|post-[-].extension` - `command` (required) - Amplify command. - `extension` (required) - by default `.js` and `.sh` are mapped to Node.js and Bash. To support more extensions or scripting runtimes, see [Adding a custom scripting runtime](#adding-a-custom-scripting-runtime). - `sub-command` (optional) - Amplify sub-command. Can be used to increase hook specificity. Example: `pre-add-auth` and `pre-mock-api`. The following is an exhaustive list of all commands along with their subcommands that are supported by Amplify CLI: commands | sub-commands **(optional)** ------------------------|------------------------ `add` |all categories (`api`, `auth`, etc.)
`codegen`
`env`
`update` |all categories (`api`, `auth`, etc.)
`env`
`remove` |all categories (`api`, `auth`, etc.)
`env`
`push` |`analytics`, `api`, `auth`, `function`, `hosting`, `interactions`, `storage`, `xr` `pull` |`env`
`publish` |- `delete` |- `checkout` |`env` `list` |`env` `get` |`env` `mock` |`api`, `storage`, `function`
`build` |`function`
`status` |`notifications`
`import` |`auth`, `storage`, `env`
`gqlcompile` |`api`
`addgraphqldatasource` |`api`
`statements` |`codegen`
`types` |`codegen`
*Note: Multiple hook scripts with the same filename are not allowed* ## Access parameters in hook scripts Command hooks receive two parameters, `data` and `error`. Amplify CLI passes parameters to hook scripts as a JSON string through standard input. ### **data** parameter structure ```json { "amplify": { "version": String, "environment": { "envName": String, "projectPath": String, "defaultEditor": String }, "command": String, "subCommand": String, "argv": [ String ] } } ``` - amplify - version - current Amplify CLI version - environment - current Amplify environment - envName - current Amplify environment name - projectPath - path to current Amplify project - defaultEditor - chosen editor in init step. Example `vscode` - command - hooked Amplify CLI command. Example: `push` - subCommand - hooked Amplify CLI subcommand or plugin. Example `auth`, `env`. - argv - list containing the arguments passed to Amplify CLI through the command line ### **error** parameter structure **error** is `undefined` if no error is emitted. Otherwise, it has the following structure: ```json { "message": String, "stack": String } ``` - message - the error message emitted by Amplify CLI - stack - the error stack emitted by Amplify CLI ### How to access command hook parameters in Node.js ```javascript const fs = require('fs'); const parameters = JSON.parse(fs.readFileSync(0, { encoding: 'utf8' })); console.log(parameters.data, parameters.error) ``` ### How to access command hook parameters in Bash First, install a JSON parser like [`jq`](https://stedolan.github.io/jq/download/). Then, parse the parameters: ```bash parameters=`cat` data=$(jq -r '.data' <<< "$parameters") error=$(jq -r '.error // empty' <<< "$parameters") echo $data echo $error ``` ## How to conditionally stop an Amplify CLI command execution To stop the execution of Amplify CLI, the hook scripts can exit with a non-zero exit code. ```js process.exit(1) ``` ```bash exit 1 ``` ## Advanced command hook configurations You can optionally add `hooks-config.json` in `amplify/hooks` to configure custom scripting runtimes or manage external dependencies. ### Adding a custom scripting runtime By default, Node.js and Bash are supported. To support additional runtimes, add `extensions` to the `hooks-config.json` file in the `amplify/hooks` folder. An example showcasing python runtime support and different runtime settings based on operating system: ```json { "extensions": { "py": { "runtime": "python3" }, "js": { "runtime": "~/.nvm/versions/node/v14.17.1/bin/node", "runtime_windows": "node", "runtime_options": ["--require", "./payload.js"], } } } ``` - The keys in the `extensions` ( js, py ) are values that will be used as `extension` in the [naming convention](#how-to-name-command-hook-scripts) used when naming the hook scripts. - `runtime` (required) - symlink (`node`, `python`, `bash`) or path to executable (`~/.nvm/versions/node/v14.17.1/bin/node`). - `runtime_windows` (optional) - windows specific symlink or path to executable. - `runtime_options` (optional) - Array of cli options to be passed to command hooks specific to runtime. ### Managing third-party dependencies Packages from external package managers like `npm` can be used in command hooks scripts. In this example, you'll install `axios` as a dependency for your Node.js hooks. First, go to the hooks folder and install the `axios` dependency. ```bash cd amplify/hooks npm init npm install axios ``` *Note*: If you use command hooks with Amplify Hosting CI/CD pipelines, you also need to have a `preBuild` step configured to install the hook dependencies: ```yaml backend: phases: preBuild: commands: - cd amplify/hooks - npm install frontend: ... ``` Dependency directories and files, such as `node_modules`, should be added to `ignore` in `hooks-config.json`. ```json { "ignore": ["node_modules", "build"] } ``` *Note*: All entries in `ignore` should follow the [.gitignore specification](http://git-scm.com/docs/gitignore). You can now use `axios` in your hook scripts placed in the `amplify/hooks` directory. ### Executing different logic based on environment When using multi-environment setup you can customize command hooks logic based on `data.amplify.environment.envName` parameter. ```javascript /** * @param data { { amplify: { environment: { envName: string, projectPath: string, defaultEditor: string }, command: string, subCommand: string, argv: string[] } } } * @param error { { message: string, stack: string } } */ const hookHandler = async (data, error) => { if (data.amplify.environment.envName === 'prod') { console.log('Executing pre-add-auth hook for prod environment'); } else if (data.amplify.environment.envName === 'dev') { console.log('Executing pre-add-auth hook for dev environment'); } }; const getParameters = async () => { const fs = require("fs"); return JSON.parse(fs.readFileSync(0, { encoding: "utf8" })); }; getParameters() .then((event) => hookHandler(event.data, event.error)) .catch((err) => { console.error(err); process.exitCode = 1; }); ``` ## Using command hooks in Amplify's CI/CD pipeline Command hooks are executed when [CI/CD builds are triggered on Amplify Hosting](https://docs.aws.amazon.com/amplify/latest/userguide/multi-environments.html). To execute hook scripts in the Amplify Hosting, add the hook scripts to the `amplify/hooks` directory and commit them to your source control. By default only `pre-push` and `post-push` hooks will be executed on builds in Amplify Hosting. To use scripting runtimes other than Node.js and Bash, see [Adding a custom scripting runtime](#adding-a-custom-scripting-runtime) and also update the **Build Settings** in Amplify Hosting to include the runtime executable. In this example, you'll add a `python` hook script running in the Amplify Hosting's CI/CD pipeline: 1. Add the python hook script along with `hooks-config.json` to the hooks directory. ```bash touch amplify/hooks/hooks-config.json ``` 2. Navigate to your app in the Amplify Hosting and select **App settings** > **Build settings** to update the `preBuild` phase to install python. ```yaml ... backend: phases: preBuild: commands: - yum install -y python3 frontend: ... ``` 3. Add `python3` to `hooks-config.json` and push the change to your source control to trigger the Amplify Hosting build. ```json { "extensions": { "py": { "runtime": "python3" } } } ``` 4. You’re all set! The python command hooks will be executed in new CI/CD builds. ## Command hook limitations with Amplify Studio Command Hooks are not executed when updating a backend via Amplify Studio.