Skip to content

Commit

Permalink
feat!: separate onSuccess events for the Fuels CLI (#2433)
Browse files Browse the repository at this point in the history
* feat: emit the `build` and `deploy` events during `fuels dev`

* chore: added `onBuild`, `onDeploy`, `onDev` and `onNode` hooks

* chore: lintfix

* chore: updated changeset

* chore: updated changeset

* chore: lintfix

* chore: update event handler structure

* chore: updated `onFailure` hook

---------

Co-authored-by: Peter Smith <peter@blueoceancomputing.co.uk>
Co-authored-by: Anderson Arboleya <anderson@arboleya.me>
Co-authored-by: Chad Nehemiah <chad.nehemiah94@gmail.com>
  • Loading branch information
4 people authored Jun 27, 2024
1 parent f11df8c commit e159582
Show file tree
Hide file tree
Showing 14 changed files with 228 additions and 64 deletions.
5 changes: 5 additions & 0 deletions .changeset/four-seas-stare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"fuels": minor
---

feat!: separate `onSuccess` events for the Fuels CLI
34 changes: 27 additions & 7 deletions apps/demo-fuels/fuels.config.full.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable no-console */
import { createConfig } from 'fuels';
import type { CommandEvent, ContractDeployOptions, FuelsConfig } from 'fuels';
import type { ContractDeployOptions, DeployedContract, FuelsConfig } from 'fuels';

const MY_FIRST_DEPLOYED_CONTRACT_NAME = '';

Expand Down Expand Up @@ -84,15 +84,35 @@ export default createConfig({
},
// #endregion deployConfig-fn

// #region onSuccess
onSuccess: (event: CommandEvent, config: FuelsConfig) => {
console.log('fuels:onSuccess', { event, config });
// #region onBuild
onBuild: (config: FuelsConfig) => {
console.log('fuels:onBuild', { config });
},
// #endregion onSuccess
// #endregion onBuild

// #region onDeploy
// #import { DeployedContract, FuelsConfig };

onDeploy: (config: FuelsConfig, data: DeployedContract[]) => {
console.log('fuels:onDeploy', { config, data });
},
// #endregion onDeploy

// #region onDev
onDev: (config: FuelsConfig) => {
console.log('fuels:onDev', { config });
},
// #endregion onDev

// #region onNode
onNode: (config: FuelsConfig) => {
console.log('fuels:onNode', { config });
},
// #endregion onNode

// #region onFailure
onFailure: (error: Error, config: FuelsConfig) => {
console.log('fuels:onFailure', { error, config });
onFailure: (config: FuelsConfig, error: Error) => {
console.log('fuels:onFailure', { config, error });
},
// #endregion onFailure

Expand Down
40 changes: 35 additions & 5 deletions apps/docs/src/guide/fuels-cli/config-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,25 +121,55 @@ Or use a function for crafting dynamic deployment flows:

<<< @../../../demo-fuels/fuels.config.full.ts#deployConfig-fn{ts:line-numbers}

## `onSuccess`
## `onBuild`

Pass a callback function to be called after a successful run.
A callback function that is called after a build event has been successful.

Parameters:

- `event` — The event that triggered this execution
- `config` — The loaded config (`fuels.config.ts`)

<<< @../../../demo-fuels/fuels.config.full.ts#onSuccess{ts:line-numbers}
<<< @../../../demo-fuels/fuels.config.full.ts#onBuild{ts:line-numbers}

## `onDeploy`

A callback function that is called after a deployment event has been successful.

Parameters:

- `config` — The loaded config (`fuels.config.ts`)
- `data` — The data (an array of deployed contracts)

<<< @../../../demo-fuels/fuels.config.full.ts#onDeploy{ts:line-numbers}

## `onDev`

A callback function that is called after the [`fuels dev`](./commands.md#fuels-dev) command has successfully restarted.

Parameters:

- `config` — The loaded config (`fuels.config.ts`)

<<< @../../../demo-fuels/fuels.config.full.ts#onDev{ts:line-numbers}

## `onNode`

A callback function that is called after the [`fuels node`](./commands.md#fuels-node) command has successfully refreshed.

Parameters:

- `config` — The loaded config (`fuels.config.ts`)

<<< @../../../demo-fuels/fuels.config.full.ts#onNode{ts:line-numbers}

## `onFailure`

Pass a callback function to be called in case of errors.

Parameters:

- `error` — Original error object
- `config` — The loaded config (`fuels.config.ts`)
- `error` — Original error object

<<< @../../../demo-fuels/fuels.config.full.ts#onFailure{ts:line-numbers}

Expand Down
48 changes: 48 additions & 0 deletions packages/fuels/src/cli/commands/build/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { fuelsConfig } from '../../../../test/fixtures/fuels.config';
import { mockLogger } from '../../../../test/utils/mockLogger';

import { build } from '.';
import * as buildSwayProgramsMod from './buildSwayPrograms';
import * as generateTypesMod from './generateTypes';

/**
* @group node
*/
describe('build', () => {
const mockAll = () => {
const { log } = mockLogger();

const onBuild = vi.fn();

const buildSwayPrograms = vi
.spyOn(buildSwayProgramsMod, 'buildSwayPrograms')
.mockResolvedValue();
const generateTypes = vi.spyOn(generateTypesMod, 'generateTypes').mockResolvedValue();

return {
onBuild,
log,
buildSwayPrograms,
generateTypes,
};
};

test('should build sway programs and generate types', async () => {
const { log, buildSwayPrograms, generateTypes } = mockAll();

await build(fuelsConfig);

expect(log).toHaveBeenCalledWith('Building..');
expect(buildSwayPrograms).toHaveBeenCalled();
expect(generateTypes).toHaveBeenCalled();
});

test('should call onBuild callback', async () => {
const { onBuild } = mockAll();
const config = { ...fuelsConfig, onBuild };

await build(config);

expect(onBuild).toHaveBeenCalledWith(config);
});
});
2 changes: 1 addition & 1 deletion packages/fuels/src/cli/commands/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ export async function build(config: FuelsConfig, program?: Command) {

await buildSwayPrograms(config);
await generateTypes(config);
config.onBuild?.(config);

const options = program?.opts();

if (options?.deploy) {
const fuelCore = await autoStartFuelCore(config);
await deploy(config);
Expand Down
40 changes: 40 additions & 0 deletions packages/fuels/src/cli/commands/deploy/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { Provider } from '@fuel-ts/account';
import { Wallet } from '@fuel-ts/account';
import { FUEL_NETWORK_URL } from '@fuel-ts/account/configs';

import { fuelsConfig } from '../../../../test/fixtures/fuels.config';
import type { DeployedContract } from '../../types';

import { deploy } from '.';
import * as createWalletMod from './createWallet';
import * as saveContractIdsMod from './saveContractIds';

/**
* @group node
*/
describe('deploy', () => {
const mockAll = () => {
const onDeploy = vi.fn();

const provider = { url: FUEL_NETWORK_URL } as Provider;
const wallet = Wallet.fromPrivateKey('0x01', provider);
const createWallet = vi.spyOn(createWalletMod, 'createWallet').mockResolvedValue(wallet);

vi.spyOn(saveContractIdsMod, 'saveContractIds').mockResolvedValue();

return {
onDeploy,
createWallet,
};
};

test('should call onDeploy callback', async () => {
const { onDeploy } = mockAll();
const expectedContracts: DeployedContract[] = [];
const config = { ...fuelsConfig, contracts: [], onDeploy };

await deploy(config);

expect(onDeploy).toHaveBeenCalledWith(config, expectedContracts);
});
});
1 change: 1 addition & 0 deletions packages/fuels/src/cli/commands/deploy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export async function deploy(config: FuelsConfig) {
}

await saveContractIds(contracts, config.output);
config.onDeploy?.(config, contracts);

return contracts;
}
11 changes: 11 additions & 0 deletions packages/fuels/src/cli/commands/dev/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ describe('dev', () => {
function mockAll() {
const { autoStartFuelCore, fuelCore, killChildProcess } = mockStartFuelCore();

const onDev = vi.fn();
const onFailure = vi.fn();

const withConfigErrorHandler = vi
Expand All @@ -50,6 +51,7 @@ describe('dev', () => {
fuelCore,
killChildProcess,
loadConfig,
onDev,
onFailure,
withConfigErrorHandler,
};
Expand All @@ -66,6 +68,15 @@ describe('dev', () => {
expect(deploy).toHaveBeenCalledTimes(1);
});

test('should call `onDev` callback on success', async () => {
const { onDev } = mockAll();
const config: FuelsConfig = { ...fuelsConfig, onDev };

await dev(config);

expect(onDev).toHaveBeenCalledWith(config);
});

it('dev should handle and log error from `buildAndDeploy`', async () => {
const { error } = mockLogger();

Expand Down
7 changes: 5 additions & 2 deletions packages/fuels/src/cli/commands/dev/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { watch } from 'chokidar';
import { globSync } from 'glob';

import { loadConfig } from '../../config/loadConfig';
import type { FuelsConfig } from '../../types';
import { type FuelsConfig } from '../../types';
import { error, log } from '../../utils/logger';
import { build } from '../build';
import { deploy } from '../deploy';
Expand All @@ -18,7 +18,10 @@ export const closeAllFileHandlers = (handlers: FSWatcher[]) => {

export const buildAndDeploy = async (config: FuelsConfig) => {
await build(config);
return deploy(config);
const deployedContracts = await deploy(config);
config.onDev?.(config);

return deployedContracts;
};

export const getConfigFilepathsToWatch = (config: FuelsConfig) => {
Expand Down
15 changes: 12 additions & 3 deletions packages/fuels/src/cli/commands/node/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ describe('node', () => {
function mockAll() {
const { autoStartFuelCore, fuelCore, killChildProcess } = mockStartFuelCore();

const onNode = vi.fn();
const onFailure = vi.fn();

const withConfigErrorHandler = vi
Expand All @@ -35,6 +36,7 @@ describe('node', () => {
fuelCore,
killChildProcess,
loadConfig,
onNode,
onFailure,
withConfigErrorHandler,
};
Expand All @@ -53,16 +55,23 @@ describe('node', () => {

test('should restart everything when config file changes', async () => {
const { log } = mockLogger();
const { autoStartFuelCore, fuelCore, killChildProcess, loadConfig, withConfigErrorHandler } =
mockAll();
const {
autoStartFuelCore,
fuelCore,
killChildProcess,
loadConfig,
withConfigErrorHandler,
onNode,
} = mockAll();

const config = structuredClone(fuelsConfig);
const config = { ...fuelsConfig, onNode };
const close = vi.fn();
const watchHandlers = [{ close }, { close }] as unknown as FSWatcher[];

await configFileChanged({ config, fuelCore, watchHandlers })('event', 'some/path');

// configFileChanged() internals
expect(onNode).toHaveBeenCalledWith(config);
expect(log).toHaveBeenCalledTimes(1);
expect(close).toHaveBeenCalledTimes(2);
expect(killChildProcess).toHaveBeenCalledTimes(1);
Expand Down
1 change: 1 addition & 0 deletions packages/fuels/src/cli/commands/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const configFileChanged = (state: NodeState) => async (_event: string, pa
try {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
await node(await loadConfig(state.config.basePath));
state.config.onNode?.(state.config);
} catch (err: unknown) {
await withConfigErrorHandler(<Error>err, state.config);
}
Expand Down
Loading

0 comments on commit e159582

Please sign in to comment.