Skip to content

Commit

Permalink
feat: introduce .squidignore (#75)
Browse files Browse the repository at this point in the history
* feat: introduce .squidingore

* refactor: extract build and upload from deploy command

* fix: build -> pack

* fix: simplify package.json check
  • Loading branch information
belopash authored Mar 6, 2024
1 parent 7ab4049 commit accff3f
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 79 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@
"fast-levenshtein": "^3.0.0",
"figlet": "^1.7.0",
"form-data": "^4.0.0",
"glob": "^10.3.10",
"ignore": "^5.3.1",
"inquirer": "^8.2.5",
"js-yaml": "^4.1.0",
"lodash": "^4.17.21",
Expand Down
216 changes: 143 additions & 73 deletions src/commands/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { promisify } from 'util';
import { Args, Flags, ux as CliUx } from '@oclif/core';
import { ManifestValue } from '@subsquid/manifest';
import chalk from 'chalk';
import { globSync } from 'glob';
import ignore from 'ignore';
import inquirer from 'inquirer';
import targz from 'targz';

Expand All @@ -21,6 +23,8 @@ const SQUID_PATH_DESC = [
` - a github URL to a git repo with a branch or commit tag`,
];

const PACKAGE_JSON = 'package.json';

const lockFiles = {
npm: 'package-lock.json',
yarn: 'yarn.lock',
Expand Down Expand Up @@ -54,6 +58,7 @@ export default class Deploy extends DeployCommand {
source: Args.string({
description: SQUID_PATH_DESC.join('\n'),
required: true,
default: '.',
}),
};

Expand Down Expand Up @@ -99,14 +104,13 @@ export default class Deploy extends DeployCommand {
const orgCode = await this.promptOrganization(org, 'using "-o" flag');

if (!isUrl) {
this.log(`🦑 Releasing the squid from local folder`);

const res = resolveManifest(source, manifestPath);
if ('error' in res) return this.error(res.error);
if ('error' in res) return this.showError(res.error, 'MANIFEST_VALIDATION_FAILED');

const { buildDir, squidDir, manifest } = res;

const archiveName = `${manifest.name}-v${manifest.version}.tar.gz`;
const squidArtifact = path.join(buildDir, archiveName);

this.log(chalk.dim(`Squid directory: ${squidDir}`));
this.log(chalk.dim(`Build directory: ${buildDir}`));
this.log(chalk.dim(`Manifest: ${manifestPath}`));
Expand Down Expand Up @@ -135,75 +139,10 @@ export default class Deploy extends DeployCommand {
}
}

if (!hasPackageJson(squidDir)) {
return this.error(
[
`The package.json file was not found in the squid directory`,
``,
`Squid directory ${squidDir}`,
``,
`Please provide a path to the root of a squid directory`,
``,
].join('\n'),
);
}

// const lockFile = get(lockFiles, manifest.build.package_manager);
// if (!hasLockFile(squidDir, lockFile)) {
// return this.error(
// [
// `${lockFile || 'Lockfile'} is not found in the squid directory`,
// ``,
// `Squid directory ${squidDir}`,
// ``,
// `Please provide a path to the root of a squid directory`,
// ``,
// ].join('\n'),
// );
// }

CliUx.ux.action.start(`◷ Compressing the squid to ${archiveName} `);

let filesCount = 0;
await compressAsync({
src: squidDir,
dest: squidArtifact,
tar: {
ignore: (name) => {
const relativePath = path.relative(path.resolve(squidDir), path.resolve(name));

switch (relativePath) {
case 'node_modules':
case 'builds':
case 'lib':
case 'Dockerfile':
// FIXME: .env ?
case '.git':
case '.github':
case '.idea':
this.log(chalk.dim(`-- ignoring ${relativePath}`));
return true;
default:
this.log(chalk.dim(`adding ${relativePath}`));

filesCount++;
return false;
}
},
},
});
CliUx.ux.action.stop(`${filesCount} file(s) ✔️`);
if (filesCount === 0) {
return this.error(`0 files were found in ${squidDir}. Please check the squid source, looks like it is empty`);
}

CliUx.ux.action.start(`◷ Uploading ${path.basename(squidArtifact)}`);
const archiveName = `${manifest.name}-v${manifest.version}.tar.gz`;

const { error, fileUrl: artifactUrl } = await uploadFile(orgCode, squidArtifact);
if (error) return this.error(error);
else if (!artifactUrl) return this.error('The artifact URL is missing');

this.log(`🦑 Releasing the squid from local folder`);
const actifactPath = await this.pack({ buildDir, squidDir, archiveName });
const artifactUrl = await this.upload({ orgCode, actifactPath });

deploy = await deploySquid({
orgCode,
Expand Down Expand Up @@ -231,10 +170,115 @@ export default class Deploy extends DeployCommand {

this.log('✔️ Done!');
}

private async pack({ buildDir, squidDir, archiveName }: { buildDir: string; squidDir: string; archiveName: string }) {
CliUx.ux.action.start(`◷ Compressing the squid to ${archiveName} `);

const squidignore = createSquidIgnore(squidDir);

if (!hasPackageJson(squidDir) || squidignore?.ignores(PACKAGE_JSON)) {
return this.showError(
[
`The ${PACKAGE_JSON} file was not found in the squid directory`,
``,
`Squid directory: ${squidDir}`,
``,
`Please provide a path to the root of a squid directory`,
``,
].join('\n'),
'PACKING_FAILED',
);
}

// const lockFile = get(lockFiles, manifest.build.package_manager);
// if (!hasLockFile(squidDir, lockFile)) {
// return this.error(
// [
// `${lockFile || 'Lockfile'} is not found in the squid directory`,
// ``,
// `Squid directory ${squidDir}`,
// ``,
// `Please provide a path to the root of a squid directory`,
// ``,
// ].join('\n'),
// );
// }

const squidArtifact = path.join(buildDir, archiveName);

let filesCount = 0;
await compressAsync({
src: squidDir,
dest: squidArtifact,
tar: {
// if squidignore does not exist, we fallback to the old ignore approach
ignore: squidignore
? (name) => {
const relativePath = path.relative(path.resolve(squidDir), path.resolve(name));

if (squidignore.ignores(relativePath)) {
this.log(chalk.dim(`-- ignoring ${relativePath}`));
return true;
} else {
this.log(chalk.dim(`adding ${relativePath}`));
filesCount++;
return false;
}
}
: (name) => {
const relativePath = path.relative(path.resolve(squidDir), path.resolve(name));

switch (relativePath) {
case 'node_modules':
case 'builds':
case 'lib':
case 'Dockerfile':
// FIXME: .env ?
case '.git':
case '.github':
case '.idea':
this.log(chalk.dim(`-- ignoring ${relativePath}`));
return true;
default:
this.log(chalk.dim(`adding ${relativePath}`));

filesCount++;
return false;
}
},
},
});

if (filesCount === 0) {
return this.showError(
`0 files were found in ${squidDir}. Please check the squid source, looks like it is empty`,
'PACKING_FAILED',
);
}

CliUx.ux.action.stop(`${filesCount} file(s) ✔️`);

return squidArtifact;
}

private async upload({ orgCode, actifactPath }: { orgCode: string; actifactPath: string }) {
CliUx.ux.action.start(`◷ Uploading ${path.basename(actifactPath)}`);

const { error, fileUrl: artifactUrl } = await uploadFile(orgCode, actifactPath);
if (error) {
return this.showError(error);
} else if (!artifactUrl) {
return this.showError('The artifact URL is missing', 'UPLOAD_FAILED');
}

CliUx.ux.action.stop('✔️');

return artifactUrl;
}
}

function hasPackageJson(squidDir: string) {
return fs.existsSync(path.join(squidDir, 'package.json'));
return fs.existsSync(path.join(squidDir, PACKAGE_JSON));
}

function hasLockFile(squidDir: string, lockFile?: string) {
Expand All @@ -244,3 +288,29 @@ function hasLockFile(squidDir: string, lockFile?: string) {
return Object.values(lockFiles).some((lf) => fs.existsSync(path.join(squidDir, lf)));
}
}

function createSquidIgnore(squidDir: string) {
const ig = ignore();

const ignoreFilePaths = globSync(['.squidignore', '**/.squidignore'], {
cwd: squidDir,
nodir: true,
posix: true,
});

if (ignoreFilePaths.length === 0) {
return undefined;
}

for (const ignoreFilePath of ignoreFilePaths) {
const ignoreCwd = path.dirname(ignoreFilePath);

const patterns = fs.readFileSync(ignoreFilePath).toString().split('\n');
for (const pattern of patterns) {
if (pattern.length === 0) continue;
ig.add(path.posix.join(ignoreCwd, pattern));
}
}

return ig;
}
8 changes: 3 additions & 5 deletions src/deploy-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,10 @@ Do you want to attach to the running deploy process?`,
});
};

showError(text: string): boolean {
CliUx.ux.action.stop('');
showError(text: string, reason?: string): never {
CliUx.ux.action.stop('');

const reason = this.deploy?.failed || 'UNEXPECTED';
reason = reason || this.deploy?.failed || 'UNEXPECTED';
const errors: (string | null)[] = [text];
if (reason === 'UNEXPECTED') {
errors.push(
Expand All @@ -190,8 +190,6 @@ Do you want to attach to the running deploy process?`,

// FIXME: maybe we should send an error report ourselves here with more details?
this.error(errors.filter(Boolean).join('\n'));

return true;
}

isFailed() {
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3228,7 +3228,7 @@ ignore@^5.1.1, ignore@^5.2.0:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==

ignore@^5.2.4:
ignore@^5.2.4, ignore@^5.3.1:
version "5.3.1"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef"
integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==
Expand Down

0 comments on commit accff3f

Please sign in to comment.