Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update command handles Dockerized sandbox #3656

Merged
merged 1 commit into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>([]);
Copy link
Contributor Author

@alexghr alexghr Dec 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left this code in in case we'll deprecate any packages in the future

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;
}
}