Skip to content

Commit

Permalink
chore: add test to verify create fuels template integrity (#2364)
Browse files Browse the repository at this point in the history
  • Loading branch information
petertonysmith94 authored May 24, 2024
1 parent 3b27bac commit 3b00bdb
Show file tree
Hide file tree
Showing 15 changed files with 231 additions and 82 deletions.
5 changes: 5 additions & 0 deletions .changeset/chilly-shirts-bathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"create-fuels": patch
---

chore: add test to verify `create fuels` template integrity
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
FUEL_NETWORK_URL=
TEST_WALLET_PVT_KEY=
PUBLISHED_NPM_VERSION=
41 changes: 41 additions & 0 deletions .github/actions/pr-release/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: "Publish PR to NPM"
inputs:
npm-token:
description: "NPM token for authenticating to NPM registry"
required: true

github-token:
description: "GitHub token for authenticating to GitHub"
required: true

pr-number:
description: "PR number"
default: ${{ github.event.pull_request.number }}

outputs:
published_version:
description: "Published version of the PR"
value: ${{ steps.release.outputs.published_version }}

runs:
using: "composite"
steps:
- name: Ensure NPM access
shell: bash
run: npm whoami
env:
NODE_AUTH_TOKEN: ${{ inputs.npm-token }}

- name: Release to @pr-${{ inputs.pr-number }} tag on npm
id: release
shell: bash
run: |
pnpm changeset:next
git add .changeset/fuel-labs-ci.md
pnpm changeset version --snapshot pr-${{ inputs.pr-number }}
changetsets=$(pnpm changeset publish --tag pr-${{ inputs.pr-number }})
published_version=$(echo "$changetsets" | grep -oP '@\K([0-9]+\.){2}[0-9]+-pr-${{ inputs.pr-number }}-\d+' | head -1)
echo "published_version=$published_version" >> $GITHUB_OUTPUT
env:
NODE_AUTH_TOKEN: ${{ inputs.npm-token }}
GITHUB_TOKEN: ${{ inputs.github-token }}
25 changes: 7 additions & 18 deletions .github/workflows/pr-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,20 @@ jobs:
- name: CI Setup
uses: ./.github/actions/ci-setup

- name: Ensure NPM access
run: npm whoami
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Build
run: pnpm build

- name: Release to @pr-${{ github.event.pull_request.number }} tag on npm
- name: Publish to NPM
id: release
run: |
pnpm changeset:next
git add .changeset/fuel-labs-ci.md
pnpm changeset version --snapshot pr-${{ env.PR_NUMBER }}
changetsets=$(pnpm changeset publish --tag pr-${{ env.PR_NUMBER }})
published_version=$(echo "$changetsets" | grep -oP '@\K([0-9]+\.){2}[0-9]+-pr-${{ env.PR_NUMBER }}-\d+' | head -1)
echo "published_version=$published_version" >> $GITHUB_OUTPUT
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
uses: ./.github/actions/pr-release
with:
npm-token: ${{ secrets.NPM_TOKEN }}
github-token: ${{ secrets.GITHUB_TOKEN }}
pr-number: ${{ github.event.pull_request.number }}

- uses: mshick/add-pr-comment@v2
with:
message: |
This PR is published in NPM with version **${{ steps.release.outputs.published_version }}**
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
13 changes: 12 additions & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,19 @@ jobs:
with:
fetch-depth: 0

- name: CI Setup
- name: Test Setup
uses: ./.github/actions/test-setup

- name: Publish PR to NPM
id: release
uses: ./.github/actions/pr-release
with:
npm-token: ${{ secrets.NPM_TOKEN }}
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Echo Published Version
run: echo ${{ steps.release.outputs.published_version }}

- name: Pretest
run: pnpm pretest

Expand All @@ -71,6 +81,7 @@ jobs:
TEST_WALLET_PVT_KEY: ${{ secrets.TEST_WALLET_PVT_KEY }}
TEST_WALLET_ADDRESS: ${{ secrets.TEST_WALLET_ADDRESS }}
FUEL_TESTNET_NETWORK_URL: ${{ secrets.FUEL_TESTNET_NETWORK_URL }}
PUBLISHED_NPM_VERSION: ${{ steps.release.outputs.published_version }}

test:
if: github.base_ref == 'master' || github.ref_name == 'master'
Expand Down
1 change: 1 addition & 0 deletions packages/create-fuels/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"prompts": "^2.4.2"
},
"devDependencies": {
"@fuel-ts/errors": "workspace:*",
"@fuel-ts/versions": "workspace:*",
"@types/prompts": "^2.4.8",
"glob": "^10.2.6"
Expand Down
70 changes: 12 additions & 58 deletions packages/create-fuels/test/cli.test.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import { mkdirSync } from 'fs';
import { glob } from 'glob';

import type { ProgramsToInclude } from '../src/cli';
import { runScaffoldCli, setupProgram } from '../src/cli';

import type { ProjectPaths } from './utils/bootstrapProject';
import { bootstrapProject, cleanupFilesystem, resetFilesystem } from './utils/bootstrapProject';
import {
bootstrapProject,
cleanupFilesystem,
copyTemplate,
resetFilesystem,
} from './utils/bootstrapProject';
import { generateArgv } from './utils/generateArgs';
import { mockLogger } from './utils/mockLogger';

const getAllFiles = async (pathToDir: string) => {
const files = await glob(`${pathToDir}/**/*`, {
ignore: ['**/node_modules/**', '**/.next/**', '**/sway-api/**'],
});
const filesWithoutPrefix = files.map((file) => file.replace(pathToDir, ''));
return filesWithoutPrefix;
};
import { filterOriginalTemplateFiles, getAllFiles } from './utils/templateFiles';

const possibleProgramsToInclude: ProgramsToInclude[] = [
{ contract: true, predicate: false, script: false },
Expand All @@ -26,51 +24,6 @@ const possibleProgramsToInclude: ProgramsToInclude[] = [
{ contract: true, predicate: true, script: true },
];

const defaultFlags = ['--pnpm'];

const generateArgs = (programsToInclude: ProgramsToInclude, projectName?: string) => {
const args = ['', ''];
if (projectName) {
args.push(projectName);
}
if (programsToInclude.contract) {
args.push('-c');
}
if (programsToInclude.predicate) {
args.push('-p');
}
if (programsToInclude.script) {
args.push('-s');
}
args.push(...defaultFlags);
return args;
};

const filterOriginalTemplateFiles = (files: string[], programsToInclude: ProgramsToInclude) => {
let newFiles = [...files];

newFiles = newFiles.filter((file) => {
if (file.includes('CHANGELOG')) {
return false;
}
if (!programsToInclude.contract && file.includes('contract')) {
return false;
}
if (!programsToInclude.predicate && file.includes('predicate')) {
return false;
}
if (!programsToInclude.script && file.includes('script')) {
return false;
}
if (['/gitignore', '/env'].includes(file)) {
return false;
}
return true;
});

return newFiles;
};

/**
* @group node
*/
Expand All @@ -80,6 +33,7 @@ describe('CLI', () => {

beforeEach(() => {
paths = bootstrapProject(__filename);
copyTemplate(paths.sourceTemplate, paths.template);
});

afterEach(() => {
Expand All @@ -95,7 +49,7 @@ describe('CLI', () => {
test.each(possibleProgramsToInclude)(
'create-fuels extracts the template to the specified directory',
async (programsToInclude) => {
const args = generateArgs(programsToInclude, paths.root);
const args = generateArgv(programsToInclude, paths.root);

await runScaffoldCli({
program: setupProgram(),
Expand All @@ -113,7 +67,7 @@ describe('CLI', () => {
);

test('create-fuels reports an error if the project directory already exists', async () => {
const args = generateArgs(
const args = generateArgv(
{
contract: true,
predicate: true,
Expand All @@ -140,7 +94,7 @@ describe('CLI', () => {
});

test('create-fuels reports an error if no programs are chosen to be included', async () => {
const args = generateArgs(
const args = generateArgv(
{
contract: false,
predicate: false,
Expand Down
65 changes: 65 additions & 0 deletions packages/create-fuels/test/e2e.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { safeExec } from '@fuel-ts/errors/test-utils';
import { execSync } from 'child_process';

import type { ProjectPaths } from './utils/bootstrapProject';
import { bootstrapProject, resetFilesystem } from './utils/bootstrapProject';
import { generateArgs } from './utils/generateArgs';
import {
filterForcBuildFiles,
filterOriginalTemplateFiles,
getAllFiles,
} from './utils/templateFiles';

const { log } = console;

const PUBLISHED_NPM_VERSION = process.env.PUBLISHED_NPM_VERSION;
const programsToInclude = { contract: true, predicate: true, script: true };
const availablePackages = ['pnpm'];

/**
* @group e2e
*/
describe('`create fuels` package integrity', () => {
let paths: ProjectPaths;
let shouldSkip = false;

beforeAll(() => {
if (!PUBLISHED_NPM_VERSION) {
log('Skipping live `create fuels` test');
shouldSkip = true;
}
});

beforeEach(() => {
paths = bootstrapProject(__filename);
});

afterEach(() => {
resetFilesystem(paths.root);
});

it.each(availablePackages)(
'should perform `%s create fuels`',
async (packageManager) => {
if (shouldSkip) {
return;
}

const args = generateArgs(programsToInclude, paths.root, packageManager).join(' ');
const expectedTemplateFiles = await getAllFiles(paths.sourceTemplate).then((files) =>
filterOriginalTemplateFiles(files, programsToInclude).filter(filterForcBuildFiles)
);

const { error: createFuelsError } = await safeExec(() =>
execSync(`${packageManager} create fuels@${PUBLISHED_NPM_VERSION} ${args}`, {
stdio: 'inherit',
})
);

const actualTemplateFiles = await getAllFiles(paths.root);
expect(createFuelsError).toBeUndefined();
expect(actualTemplateFiles.sort()).toEqual(expectedTemplateFiles.sort());
},
{ timeout: 30000 }
);
});
11 changes: 8 additions & 3 deletions packages/create-fuels/test/utils/bootstrapProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { basename, join } from 'path';
export type ProjectPaths = {
root: string;
template: string;
sourceTemplate: string;
};

/**
Expand All @@ -21,9 +22,6 @@ export const bootstrapProject = (
// Template paths
const templateDir = join(templatesDir, templateName);
const localTemplateDir = join(testTemplateDir, templateName);
if (!existsSync(localTemplateDir)) {
cpSync(templateDir, localTemplateDir, { recursive: true });
}

// Unique name
const testFilename = basename(testFilepath.replace(/\./g, '-'));
Expand All @@ -35,9 +33,16 @@ export const bootstrapProject = (
return {
root,
template: localTemplateDir,
sourceTemplate: templateDir,
};
};

export const copyTemplate = (srcDir: string, destDir: string) => {
if (!existsSync(destDir)) {
cpSync(srcDir, destDir, { recursive: true });
}
};

export const resetFilesystem = (dirPath: string) => {
if (existsSync(dirPath)) {
rmSync(dirPath, { recursive: true });
Expand Down
28 changes: 28 additions & 0 deletions packages/create-fuels/test/utils/generateArgs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { ProgramsToInclude } from '../../src/cli';

export const generateArgs = (
programsToInclude: ProgramsToInclude,
projectName?: string,
packageManager: string = 'pnpm'
): string[] => {
const args = [];
if (projectName) {
args.push(projectName);
}
if (programsToInclude.contract) {
args.push('-c');
}
if (programsToInclude.predicate) {
args.push('-p');
}
if (programsToInclude.script) {
args.push('-s');
}
args.push(`--${packageManager}`);
return args;
};

export const generateArgv = (
programsToInclude: ProgramsToInclude,
projectName?: string
): string[] => ['', '', ...generateArgs(programsToInclude, projectName)];
Loading

0 comments on commit 3b00bdb

Please sign in to comment.