Skip to content

Commit

Permalink
chore: inform users if their fuels version is outdated (#3108)
Browse files Browse the repository at this point in the history
* test `reportUserVersion`

* move util to `versions` package

* export via cli and not index

* log fuels version

* fetch latest version

* log out comparison

* add changeset

* fix tests

* disable pr release

* add tests

* re-use `getBuiltinVersions`

* move to `fuels` CLI from `versions`

* revert test changes

* revert tests

* add tests

* add testing group

* add changeset

* add a test case

* print a msg if fetch fails

* add error msg in one more place

* fix test

---------

Co-authored-by: Chad Nehemiah <chad.nehemiah94@gmail.com>
  • Loading branch information
2 people authored and nedsalk committed Sep 17, 2024
1 parent 8235b4e commit 5e55da8
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 1 deletion.
6 changes: 6 additions & 0 deletions .changeset/eleven-jeans-matter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@fuel-ts/versions": patch
"fuels": patch
---

chore: inform users if their `fuels` version is outdated
68 changes: 68 additions & 0 deletions packages/fuels/src/cli/utils/checkForAndDisplayUpdates.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import * as versionsMod from '@fuel-ts/versions';

import * as checkForAndDisplayUpdatesMod from './checkForAndDisplayUpdates';
import * as loggerMod from './logger';

/**
* @group node
*/
describe('checkForAndDisplayUpdates', () => {
beforeEach(() => {
vi.resetAllMocks();
});

afterEach(() => {
vi.restoreAllMocks();
});

const mockDeps = (params: { latestVersion: string; userVersion: string }) => {
const { latestVersion, userVersion } = params;
vi.spyOn(Promise, 'race').mockReturnValue(Promise.resolve(latestVersion));

vi.spyOn(versionsMod, 'versions', 'get').mockReturnValue({
FUELS: userVersion,
FORC: '1.0.0',
FUEL_CORE: '1.0.0',
});

const log = vi.spyOn(loggerMod, 'log');
const warn = vi.spyOn(loggerMod, 'warn');

return { log, warn };
};

test('should fail gracefully if the fetch fails', async () => {
vi.spyOn(global, 'fetch').mockImplementation(() =>
Promise.reject(new Error('Failed to fetch'))
);
const log = vi.spyOn(loggerMod, 'log');
await expect(checkForAndDisplayUpdatesMod.checkForAndDisplayUpdates()).resolves.not.toThrow();
expect(log).toHaveBeenCalledWith('\n Unable to fetch latest fuels version. Skipping...\n');
});

test('should log a warning if the version is outdated', async () => {
const { warn } = mockDeps({ latestVersion: '1.0.1', userVersion: '1.0.0' });
await checkForAndDisplayUpdatesMod.checkForAndDisplayUpdates();
expect(warn).toHaveBeenCalledWith(
'\n⚠️ There is a newer version of fuels available: 1.0.1. Your version is: 1.0.0\n'
);
});

test('should log a success message if the version is up to date', async () => {
const { log } = mockDeps({ latestVersion: '1.0.0', userVersion: '1.0.0' });
await checkForAndDisplayUpdatesMod.checkForAndDisplayUpdates();
expect(log).toHaveBeenCalledWith('\n✅ Your fuels version is up to date: 1.0.0\n');
});

test('should handle fetch timing out', async () => {
vi.spyOn(global, 'fetch').mockImplementation(
() =>
new Promise((resolve) => {
setTimeout(resolve, 5000);
})
);
const log = vi.spyOn(loggerMod, 'log');
await expect(checkForAndDisplayUpdatesMod.checkForAndDisplayUpdates()).resolves.not.toThrow();
expect(log).toHaveBeenCalledWith('\n Unable to fetch latest fuels version. Skipping...\n');
});
});
43 changes: 43 additions & 0 deletions packages/fuels/src/cli/utils/checkForAndDisplayUpdates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { versions, gt, eq } from '@fuel-ts/versions';

import { warn, log } from './logger';

export const getLatestFuelsVersion = async () => {
const response = await fetch('https://registry.npmjs.org/fuels/latest');
const data = await response.json();
return data.version as string;
};

export const checkForAndDisplayUpdates = async () => {
try {
const { FUELS: userFuelsVersion } = versions;

const latestFuelsVersion = await Promise.race<string | undefined>([
new Promise((resolve) => {
setTimeout(resolve, 3000);
}),
getLatestFuelsVersion(),
]);

if (!latestFuelsVersion) {
log(`\n Unable to fetch latest fuels version. Skipping...\n`);
return;
}

const isFuelsVersionOutdated = gt(latestFuelsVersion, userFuelsVersion);
const isFuelsVersionUpToDate = eq(latestFuelsVersion, userFuelsVersion);

if (isFuelsVersionOutdated) {
warn(
`\n⚠️ There is a newer version of fuels available: ${latestFuelsVersion}. Your version is: ${userFuelsVersion}\n`
);
return;
}

if (isFuelsVersionUpToDate) {
log(`\n✅ Your fuels version is up to date: ${userFuelsVersion}\n`);
}
} catch {
log(`\n Unable to fetch latest fuels version. Skipping...\n`);
}
};
4 changes: 3 additions & 1 deletion packages/fuels/src/run.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { configureCli } from './cli';
import { checkForAndDisplayUpdates } from './cli/utils/checkForAndDisplayUpdates';
import { error } from './cli/utils/logger';

export const run = async (argv: string[]) => {
const program = configureCli();
return program.parseAsync(argv);
return Promise.all([await checkForAndDisplayUpdates().catch(error), program.parseAsync(argv)]);
};
1 change: 1 addition & 0 deletions packages/versions/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ export const versions = getBuiltinVersions();

export * from './lib/types';
export * from './lib/checkFuelCoreVersionCompatibility';
export * from './lib/semver';

0 comments on commit 5e55da8

Please sign in to comment.