Skip to content

Commit

Permalink
feat: update command handles Dockerized sandbox (#3656)
Browse files Browse the repository at this point in the history
This PR cherry-picks some of the changes from #3567

1. It no longer fails if it doesn't detect package.json. So it can now
be used to update contracts on their own aztec-cli update --contract
path/to/some/folder
2. Instead of looking for the latest @aztec/aztec-sandbox, it now looks
for the latest @aztec/aztec.js.
3. Prints a reminder to the user to update Docker containers and links
to update instructions.
  • Loading branch information
alexghr authored Dec 12, 2023
1 parent 12249bf commit 7c85750
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 84 deletions.
5 changes: 3 additions & 2 deletions yarn-project/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -483,11 +483,12 @@ export function getProgram(log: LogFn, debugLogger: DebugLogger): Command {
.description('Updates Nodejs and Noir dependencies')
.argument('[projectPath]', 'Path to the project directory', process.cwd())
.option('--contract [paths...]', 'Paths to contracts to update dependencies', [])
.option('--sandbox-version <semver>', 'The sandbox version to update to. Defaults to latest', 'latest')
.option('--aztec-version <semver>', 'The version to update Aztec packages to. Defaults to latest', 'latest')
.addOption(pxeOption)
.action(async (projectPath: string, options) => {
const { update } = await import('./update/update.js');
await update(projectPath, options.contract, options.rpcUrl, options.sandboxVersion, log, debugLogger);
const { contract, aztecVersion, rpcUrl } = options;
await update(projectPath, contract, rpcUrl, aztecVersion, log);
});

addNoirCompilerCommanderActions(program, log);
Expand Down
20 changes: 20 additions & 0 deletions yarn-project/cli/src/update/npm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ import { SemVer, parse } from 'semver';
import { atomicUpdateFile } from '../utils.js';
import { DependencyChanges } from './common.js';

const deprecatedNpmPackages = new Set<string>([]);
const npmDeprecationMessage = `
The following packages have been deprecated and will no longer be updated on the npm registry:
${Array.from(deprecatedNpmPackages)
.map(pkg => ` - ${pkg}`)
.join('\n')}
Remove them from package.json
`;

/**
* Looks up a package.json file and returns its contents
* @param projectPath - Path to Nodejs project
Expand Down Expand Up @@ -68,6 +77,8 @@ export async function updateAztecDeps(
log(`Updating @aztec packages to ${aztecVersion} in ${relative(process.cwd(), changes.file)}`);
const version = aztecVersion.version;

let detectedDeprecatedPackages = false;

for (const depType of ['dependencies', 'devDependencies'] as const) {
const dependencies = pkg[depType];
if (!dependencies) {
Expand All @@ -84,6 +95,11 @@ export async function updateAztecDeps(
continue;
}

if (deprecatedNpmPackages.has(name)) {
detectedDeprecatedPackages = true;
continue;
}

if (dependencies[name] !== version) {
changes.dependencies.push({
name,
Expand All @@ -96,6 +112,10 @@ export async function updateAztecDeps(
}
}

if (detectedDeprecatedPackages) {
log(npmDeprecationMessage);
}

if (changes.dependencies.length > 0) {
const contents = JSON.stringify(pkg, null, 2) + '\n';
await atomicUpdateFile(resolve(join(projectPath, 'package.json')), contents);
Expand Down
111 changes: 29 additions & 82 deletions yarn-project/cli/src/update/update.ts
Original file line number Diff line number Diff line change
@@ -1,84 +1,68 @@
/* eslint-disable jsdoc/require-jsdoc */
import { DebugLogger, LogFn } from '@aztec/foundation/log';
import { LogFn } from '@aztec/foundation/log';

import { relative, resolve } from 'path';
import { SemVer, coerce, gt, lt, parse } from 'semver';
import { parse } from 'semver';

import { createCompatibleClient } from '../client.js';
import { GITHUB_TAG_PREFIX } from '../github.js';
import { DependencyChanges } from './common.js';
import { updateAztecNr } from './noir.js';
import { getNewestVersion as getLatestVersion, readPackageJson, updateAztecDeps, updateLockfile } from './npm.js';
import { getNewestVersion, updateAztecDeps, updateLockfile } from './npm.js';

const SANDBOX_PACKAGE = '@aztec/aztec-sandbox';
const AZTECJS_PACKAGE = '@aztec/aztec.js';
const UPDATE_DOCS_URL = 'https://docs.aztec.network/dev_docs/updating';

export async function update(
projectPath: string,
contracts: string[],
pxeUrl: string,
sandboxVersion: string,
aztecVersion: string,
log: LogFn,
debugLog: DebugLogger,
): Promise<void> {
const targetSandboxVersion =
sandboxVersion === 'latest' ? await getLatestVersion(SANDBOX_PACKAGE, 'latest') : parse(sandboxVersion);
const targetAztecVersion =
aztecVersion === 'latest' ? await getNewestVersion(AZTECJS_PACKAGE, 'latest') : parse(aztecVersion);

if (!targetSandboxVersion) {
throw new Error(`Invalid aztec version ${sandboxVersion}`);
if (!targetAztecVersion) {
throw new Error(`Invalid aztec version ${aztecVersion}`);
}

let currentSandboxVersion = await getNpmSandboxVersion(projectPath, log);

if (!currentSandboxVersion) {
currentSandboxVersion = await getRemoteSandboxVersion(pxeUrl, log, debugLog);

if (currentSandboxVersion && lt(currentSandboxVersion, targetSandboxVersion)) {
log(`
Sandbox is older than version ${targetSandboxVersion}. If running via docker-compose, follow update instructions:
https://docs.aztec.network/dev_docs/cli/updating
Once the sandbox is updated, run the \`aztec-cli update\` command again`);
return;
const projectDependencyChanges: DependencyChanges[] = [];
try {
const npmChanges = await updateAztecDeps(resolve(process.cwd(), projectPath), targetAztecVersion, log);
if (npmChanges.dependencies.length > 0) {
updateLockfile(projectPath, log);
}
}

if (!currentSandboxVersion) {
throw new Error('Sandbox version could not be detected');
}

// sanity check
if (gt(currentSandboxVersion, targetSandboxVersion)) {
throw new Error('Local sandbox version is newer than latest version.');
}

const npmChanges = await updateAztecDeps(projectPath, targetSandboxVersion, log);
if (npmChanges.dependencies.length > 0) {
updateLockfile(projectPath, log);
projectDependencyChanges.push(npmChanges);
} catch (err) {
if (err instanceof Error && 'code' in err && err.code === 'ENOENT') {
log(`No package.json found in ${projectPath}. Skipping npm update...`);
} else {
throw err;
}
}

const contractChanges: DependencyChanges[] = [];
for (const contract of contracts) {
try {
contractChanges.push(
projectDependencyChanges.push(
await updateAztecNr(
resolve(projectPath, contract),
`${GITHUB_TAG_PREFIX}-v${targetSandboxVersion.version}`,
resolve(process.cwd(), projectPath, contract),
`${GITHUB_TAG_PREFIX}-v${targetAztecVersion.version}`,
log,
),
);
} catch (err) {
if (err instanceof Error && 'code' in err && err.code === 'ENOENT') {
log(`No Nargo.toml found in ${relative(process.cwd(), contract)}. Skipping...`);
process.exit(1);
} else {
throw err;
}

throw err;
}
}

printChanges(npmChanges, log);
log(`To update Docker containers follow instructions at ${UPDATE_DOCS_URL}`);

contractChanges.forEach(changes => {
projectDependencyChanges.forEach(changes => {
printChanges(changes, log);
});
}
Expand All @@ -93,40 +77,3 @@ function printChanges(changes: DependencyChanges, log: LogFn): void {
});
}
}

async function getNpmSandboxVersion(projectPath: string, log: LogFn): Promise<SemVer | null> {
try {
const pkg = await readPackageJson(projectPath);
// use coerce instead of parse because it eliminates semver operators like ~ and ^
if (pkg.dependencies?.[SANDBOX_PACKAGE]) {
return coerce(pkg.dependencies[SANDBOX_PACKAGE]);
} else if (pkg.devDependencies?.[SANDBOX_PACKAGE]) {
return coerce(pkg.devDependencies[SANDBOX_PACKAGE]);
} else {
return null;
}
} catch (err) {
if (err instanceof Error && 'code' in err && err.code === 'ENOENT') {
log(`No package.json found in ${projectPath}`);
process.exit(1);
}

throw err;
}
}

async function getRemoteSandboxVersion(pxeUrl: string, log: LogFn, debugLog: DebugLogger): Promise<SemVer | null> {
try {
const client = await createCompatibleClient(pxeUrl, debugLog);
const nodeInfo = await client.getNodeInfo();

return parse(nodeInfo.sandboxVersion);
} catch (err) {
if (err instanceof Error && err.message === 'fetch failed') {
log(`Could not connect to Sandbox running on ${pxeUrl}`);
process.exit(1);
}

throw err;
}
}

0 comments on commit 7c85750

Please sign in to comment.