Skip to content

Commit

Permalink
feat: add deploy flag to fuels cli build command (#1419)
Browse files Browse the repository at this point in the history
  • Loading branch information
arboleya authored Nov 9, 2023
1 parent 0ee6377 commit dd93182
Show file tree
Hide file tree
Showing 12 changed files with 141 additions and 33 deletions.
12 changes: 11 additions & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,15 @@
"access": "public",
"baseBranch": "master",
"updateInternalDependencies": "patch",
"ignore": ["fuel-gauge"]
"ignore": [
"fuel-gauge",
"docs",
"demo-fuels",
"demo-react-cra",
"demo-react-vite",
"demo-nextjs",
"demo-node-esm",
"demo-typegen",
"@fuel-ts/docs-snippets"
]
}
5 changes: 5 additions & 0 deletions .changeset/light-cameras-tease.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"fuels": patch
---

Adding new flag to Fuels CLI build command
24 changes: 24 additions & 0 deletions apps/docs/src/guide/cli/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,37 @@ In a nutshell:

## `fuels build`

```console
npx fuels help build
```

```
Options:
-p, --path <path> Path to project root (default: "/Users/anderson/Code/fuel/fuels-ts/apps/docs")
-d, --deploy Deploy contracts after build (auto-starts a `fuel-core` node if needed)
-h, --help Display help
```

Examples:

```console
npx fuels build
```

1. Build all Sway programs under your `workspace` using `forc` <sup>[1](#commands-for-wrapped-utiltities)</sup>
1. Generate types for them using `fuels-typegen` <sup>[2](#typegen)</sup>

```console
npx fuels build --deploy
```

Using the `--deploy` flag will aditionally:

1. Auto-start a short-lived `fuel-core` node if _needed_ ([docs](./config-file.md#autostartfuelcore))
2. Run `deploy` on that node

> _This is useful when working with contracts because a contract's ID is generated only on deployment._
## `fuels deploy`

```console
Expand Down
4 changes: 4 additions & 0 deletions packages/fuels/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ export const configureCli = () => {
(command = program.command(Commands.build))
.description('Build Sway programs and generate Typescript for them')
.addOption(pathOption)
.option(
'-d, --deploy',
'Deploy contracts after build (auto-starts a `fuel-core` node if needed)'
)
.action(withConfig(command, Commands.build, build));

(command = program.command(Commands.deploy))
Expand Down
15 changes: 14 additions & 1 deletion packages/fuels/src/cli/commands/build/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
import { type Command } from 'commander';

import type { FuelsConfig } from '../../types';
import { log } from '../../utils/logger';
import { deploy } from '../deploy';
import { autoStartFuelCore } from '../dev/startFuelCore';

import { buildSwayPrograms } from './buildSwayPrograms';
import { generateTypes } from './generateTypes';

export async function build(config: FuelsConfig) {
export async function build(config: FuelsConfig, program?: Command) {
log('Building..');

await buildSwayPrograms(config);
await generateTypes(config);

const options = program?.opts();

if (options?.deploy) {
const fuelCore = await autoStartFuelCore(config);
await deploy(config);
fuelCore?.killChildProcess();
}
}
13 changes: 2 additions & 11 deletions packages/fuels/src/cli/commands/dev/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ import { build } from '../build';
import { deploy } from '../deploy';
import { withConfigErrorHandler } from '../withConfig';

import { defaultConsensusKey } from './defaultChainConfig';
import type { FuelCoreNode } from './startFuelCore';
import { startFuelCore } from './startFuelCore';
import { autoStartFuelCore } from './startFuelCore';

export const closeAllFileHandlers = (handlers: FSWatcher[]) => {
handlers.forEach((h) => h.close());
Expand Down Expand Up @@ -56,15 +55,7 @@ export const configFileChanged = (state: DevState) => async (_event: string, pat
};

export const dev = async (config: FuelsConfig) => {
let fuelCore: FuelCoreNode | undefined;

if (config.autoStartFuelCore) {
fuelCore = await startFuelCore(config);
// eslint-disable-next-line no-param-reassign
config.providerUrl = fuelCore.providerUrl;
// eslint-disable-next-line no-param-reassign
config.privateKey = defaultConsensusKey;
}
const fuelCore = await autoStartFuelCore(config);

const configFilePaths = getConfigFilepathsToWatch(config);

Expand Down
14 changes: 14 additions & 0 deletions packages/fuels/src/cli/commands/dev/startFuelCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,17 @@ export const startFuelCore = async (config: FuelsConfig): Promise<FuelCoreNode>
core.on('error', reject);
});
};

export const autoStartFuelCore = async (config: FuelsConfig) => {
let fuelCore: FuelCoreNode | undefined;

if (config.autoStartFuelCore) {
fuelCore = await startFuelCore(config);
// eslint-disable-next-line no-param-reassign
config.providerUrl = fuelCore.providerUrl;
// eslint-disable-next-line no-param-reassign
config.privateKey = defaultConsensusKey;
}

return fuelCore;
};
7 changes: 5 additions & 2 deletions packages/fuels/src/cli/commands/withConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ export const withConfigErrorHandler = async (err: Error, config?: FuelsConfig) =
export function withConfig<CType extends Commands>(
program: Command,
command: CType,
fn: (config: FuelsConfig) => Promise<Extract<CommandEvent, { type: CType }>['data']>
fn: (
config: FuelsConfig,
options?: Command
) => Promise<Extract<CommandEvent, { type: CType }>['data']>
) {
return async () => {
const options = program.opts();
Expand All @@ -30,7 +33,7 @@ export function withConfig<CType extends Commands>(
}

try {
const eventData = await fn(config);
const eventData = await fn(config, program);
config.onSuccess?.(
{
type: command,
Expand Down
33 changes: 33 additions & 0 deletions packages/fuels/test/features/build.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { existsSync } from 'fs';
import { join } from 'path';

import * as deployMod from '../../src/cli/commands/deploy/index';
import { mockStartFuelCore } from '../utils/mockStartFuelCore';
import { resetDiskAndMocks } from '../utils/resetDiskAndMocks';
import {
buildFlagsDeploy,
contractsFooDir,
generatedDir,
initFlagsUseBuiltinBinaries,
Expand All @@ -14,7 +17,16 @@ describe('build', () => {
beforeEach(resetDiskAndMocks);
afterEach(resetDiskAndMocks);

function mockAll() {
const { startFuelCore, killChildProcess } = mockStartFuelCore();
const deploy = jest.spyOn(deployMod, 'deploy').mockImplementation();

return { startFuelCore, killChildProcess, deploy };
}

it('should run `build` command', async () => {
const { startFuelCore, killChildProcess, deploy } = mockAll();

await runInit();
await runBuild();

Expand All @@ -34,9 +46,15 @@ describe('build', () => {
].map((f) => join(__dirname, '..', 'fixtures', 'generated', f));

files.forEach((file) => expect(existsSync(file)).toBeTruthy());

expect(startFuelCore).toHaveBeenCalledTimes(0);
expect(deploy).toHaveBeenCalledTimes(0);
expect(killChildProcess).toHaveBeenCalledTimes(0);
});

it('should run `build` command with contracts-only', async () => {
const { startFuelCore, killChildProcess, deploy } = mockAll();

await runInit([initFlagsUseBuiltinBinaries, '-c', contractsFooDir, '-o', generatedDir].flat());
await runBuild();

Expand All @@ -49,5 +67,20 @@ describe('build', () => {
].map((f) => join(__dirname, '..', 'fixtures', 'generated', f));

files.forEach((file) => expect(existsSync(file)).toBeTruthy());

expect(startFuelCore).toHaveBeenCalledTimes(0);
expect(deploy).toHaveBeenCalledTimes(0);
expect(killChildProcess).toHaveBeenCalledTimes(0);
});

it('should run `build` command with `--deploy` flag', async () => {
const { startFuelCore, killChildProcess, deploy } = mockAll();

await runInit();
await runBuild([buildFlagsDeploy]);

expect(startFuelCore).toHaveBeenCalledTimes(1);
expect(deploy).toHaveBeenCalledTimes(1);
expect(killChildProcess).toHaveBeenCalledTimes(1);
});
});
21 changes: 5 additions & 16 deletions packages/fuels/test/features/dev.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import * as chokidar from 'chokidar';

import type { FuelsConfig } from '../../src';
import * as buildMod from '../../src/cli/commands/build/index';
import * as deployMod from '../../src/cli/commands/deploy/index';
import * as startCoreMod from '../../src/cli/commands/dev/startFuelCore';
import { mockLogger } from '../utils/mockLogger';
import { mockStartFuelCore } from '../utils/mockStartFuelCore';
import { resetDiskAndMocks } from '../utils/resetDiskAndMocks';
import { runInit, runDev } from '../utils/runCommands';

Expand All @@ -20,18 +19,7 @@ describe('dev', () => {
function mockAll() {
mockLogger();

const startFuelCore = jest
.spyOn(startCoreMod, 'startFuelCore')
.mockImplementation((_config: FuelsConfig) =>
Promise.resolve({
bindIp: '0.0.0.0',
accessIp: '127.0.0.1',
port: 4000,
providerUrl: `http://127.0.0.1:4000/graphql`,
killChildProcess: jest.fn(),
chainConfig: '/some/path/chainConfig.json',
})
);
const { startFuelCore, killChildProcess } = mockStartFuelCore();

const build = jest.spyOn(buildMod, 'build').mockImplementation();
const deploy = jest.spyOn(deployMod, 'deploy').mockImplementation();
Expand All @@ -41,16 +29,17 @@ describe('dev', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const watch = jest.spyOn(chokidar, 'watch').mockReturnValue({ on } as any);

return { startFuelCore, build, deploy, on, watch };
return { startFuelCore, killChildProcess, build, deploy, on, watch };
}

it('should run `dev` command', async () => {
const { startFuelCore, build, deploy, on, watch } = mockAll();
const { startFuelCore, killChildProcess, build, deploy, on, watch } = mockAll();

await runInit();
await runDev();

expect(startFuelCore).toHaveBeenCalledTimes(1);
expect(killChildProcess).toHaveBeenCalledTimes(0);
expect(build).toHaveBeenCalledTimes(1);
expect(deploy).toHaveBeenCalledTimes(1);

Expand Down
21 changes: 21 additions & 0 deletions packages/fuels/test/utils/mockStartFuelCore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { FuelsConfig } from '../../src';
import * as startFuelCoreMod from '../../src/cli/commands/dev/startFuelCore';

export const mockStartFuelCore = () => {
const killChildProcess = jest.fn();

const startFuelCore = jest
.spyOn(startFuelCoreMod, 'startFuelCore')
.mockImplementation((_config: FuelsConfig) =>
Promise.resolve({
bindIp: '0.0.0.0',
accessIp: '127.0.0.1',
port: 4000,
providerUrl: `http://127.0.0.1:4000/graphql`,
killChildProcess,
chainConfig: '/some/path/chainConfig.json',
})
);

return { startFuelCore, killChildProcess };
};
5 changes: 3 additions & 2 deletions packages/fuels/test/utils/runCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export const initFlagsDefault = [
initFlagsUseBuiltinBinaries,
initFlagsAutoStartFuelCore,
];
export const buildFlagsDeploy = '--deploy';

/**
* Command callers
Expand All @@ -55,8 +56,8 @@ export async function runInit(flags: string[] = initFlagsDefault.flat()) {
return runCommand(Commands.init, flags);
}

export async function runBuild() {
return runCommand(Commands.build);
export async function runBuild(flags: string[] = []) {
return runCommand(Commands.build, flags);
}

export async function runDeploy() {
Expand Down

0 comments on commit dd93182

Please sign in to comment.