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

synthetic-chain package and CLI #46

Merged
merged 5 commits into from
Jan 6, 2024
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
9 changes: 6 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,18 @@ jobs:
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

# The .ts scripts depend upon this
# The .ts scripts depend upon this
- run: npm install --global tsx
# Enable corepack for packageManager config
- run: corepack enable
- run: yarn install

- name: build test images
run: |
docker info
./buildTestImages.ts
node_modules/.bin/synthetic-chain build
Copy link
Member

Choose a reason for hiding this comment

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

Is it more idiomatic to do this?

Suggested change
node_modules/.bin/synthetic-chain build
yarn synthetic-chain build

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes but that's not working. I'll take another crack at it after the other items

- name: run test images
run: ./runTestImages.ts
run: node_modules/.bin/synthetic-chain test

# XXX this should be instant because all the stages were already built in the steps above
# but it's re-building the last stage. This is deemed good enough for now.
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ web_modules/

# Output of 'npm pack'
*.tgz
!agoric-synthetic-chain-*.tgz

# Yarn Integrity file
.yarn-integrity
Expand Down Expand Up @@ -134,3 +135,4 @@ dist

# build in CI
Dockerfile
/upgrade-test-scripts
File renamed without changes.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,21 @@ If the proposal is _pending_ and does not yet have a number, use a letter. The p
To build the test images,

```
./buildTestImages.ts
node_modules/.bin/synthetic-chain build
```

To build the test images for particular proposals,

```
# build just upgrades
./buildTestImages.ts --match upgrade
node_modules/.bin/synthetic-chain build --match upgrade
```

To run the tests for particular proposals,

```
# build just upgrades
./runTestImages.ts --match upgrade
node_modules/.bin/synthetic-chain test --match upgrade
```

## Debugging
Expand Down
37 changes: 0 additions & 37 deletions buildTestImages.ts

This file was deleted.

35 changes: 0 additions & 35 deletions debugTestImage.ts

This file was deleted.

15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"private": true,
"workspaces": [
"packages/*"
],
"scripts": {
"build": "echo Use synthetic-chain to build proposal images",
"test": "echo Use synthetic-chain to test proposal images"
},
"dependencies": {
"@agoric/synthetic-chain": "workspace:*"
Comment on lines +10 to +11
Copy link
Member

Choose a reason for hiding this comment

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

I'm not familiar with workspace:*.
I suppose I should look it up...

},
"license": "Apache-2.0",
"packageManager": "[email protected]"
}
29 changes: 29 additions & 0 deletions packages/synthetic-chain/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Synthetic chain tools

Utilities to build a synthetic chain and test running proposals atop it. The chain approximates agoric-3 (Mainnet) using the state from https://github.com/Agoric/agoric-3-proposals (It could trivially support other Agoric chains, if we scale horizontally.)

## Design

Builds atop the `main` image of https://ghcr.io/agoric/agoric-3-proposals to execute proposals on top of the agoric-3 chain and also test them.

It also adopts the multi-stage Docker build flow from the a3p repo. See https://github.com/Agoric/agoric-3-proposals?tab=readme-ov-file#design

One deficiency in the current design is that share code in `upgrade-test-scripts` is not versioned or packaged. Any change to it will invalidate the base image. And each layer assumes it has the latest. And now with this repo, the local copy has to be kept in sync with the base image and the a3p repo.

```sh
node_modules/.bin/synthetic-chain build

node_modules/.bin/synthetic-chain test

node_modules/.bin/synthetic-chain test --debug -m <substring of proposal name>
```

shared JS is exported from the package.
non-JS is in `files` and can be untarred out for use in a3p

To depend on `@agoric/synthetic-chain` that isn't yet published, use `npm pack` in this package and copy the tgz into the proposal. Then use the `file:` protocol in the package.json to add it. Finally `yarn install` in the package to update local node_modules for linting. E.g.,

```json
"dependencies": {
"@agoric/synthetic-chain": "file:agoric-synthetic-chain-0.0.1-alpha.tgz",
```
55 changes: 55 additions & 0 deletions packages/synthetic-chain/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/env tsx

import { parseArgs } from 'node:util';
import path from 'node:path';
import { execSync } from 'node:child_process';
import { buildProposalSubmissions, buildTestImages } from './src/cli/build.js';
import { refreshDockerfile } from './src/cli/dockerfileGen.js';
import { matchOneProposal, readProposals } from './src/cli/proposals.js';
import { debugTestImage, runTestImages } from './src/cli/run.js';

const { positionals, values } = parseArgs({
options: {
match: { short: 'm', type: 'string' },
dry: { type: 'boolean' },
debug: { type: 'boolean' },
},
allowPositionals: true,
});

const allProposals = readProposals(path.resolve('.'));

const { match } = values;
const proposals = match
? allProposals.filter(p => p.proposalName.includes(match))
: allProposals;

const [cmd] = positionals;

// TODO consider a lib like Commander for auto-gen help
const usage = `USAGE:
build

test [--debug]
`;

switch (cmd) {
case 'build':
execSync(
// XXX very brittle
'cp -r node_modules/@agoric/synthetic-chain/upgrade-test-scripts .',
);
refreshDockerfile(allProposals);
buildProposalSubmissions(proposals);
buildTestImages(proposals, values.dry);
break;
case 'test':
if (values.debug) {
debugTestImage(matchOneProposal(proposals, match!));
} else {
runTestImages(proposals);
}
break;
default:
console.log(usage);
}
34 changes: 34 additions & 0 deletions packages/synthetic-chain/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "@agoric/synthetic-chain",
"version": "0.0.1-alpha",
"description": "Utilities to build a chain and test proposals atop it",
"bin": "./cli.ts",
"main": "index.js",
"type": "module",
"files": [
"index.js",
"cli.ts",
"src",
"upgrade-test-scripts"
],
"scripts": {
"build": "echo No build step",
"test": "NODE_OPTIONS='--loader=tsx --no-warnings' ava",
"test:xs": "exit 0"
},
"dependencies": {
"tsx": "^3.12.8",
"typescript": "^5.3.3"
},
"devDependencies": {
"@types/node": "^18.11.9",
"ava": "^5.3.0"
},
"ava": {
"extensions": {
"js": true,
"ts": "module"
}
},
"license": "Apache-2.0"
}
48 changes: 48 additions & 0 deletions packages/synthetic-chain/src/cli/build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { execSync } from 'node:child_process';
import path from 'node:path';
import { ProposalInfo, imageNameForProposal } from './proposals.js';

export const buildProposalSubmissions = (proposals: ProposalInfo[]) => {
for (const proposal of proposals) {
if (!('source' in proposal && proposal.source === 'build')) continue;

console.log(
'Refreshing submission for',
proposal.proposalIdentifier,
proposal.proposalName,
);
const { buildScript } = proposal;
const proposalPath = `proposals/${proposal.proposalIdentifier}:${proposal.proposalName}`;
const submissionPath = `${proposalPath}/submission`;
const relativeBuildScript = path.relative(submissionPath, buildScript);

execSync(`mkdir -p ${submissionPath}`);
// Generate files only in submission path.
execSync(`agoric run ${relativeBuildScript}`, {
cwd: submissionPath,
env: { ...process.env, HOME: '.' },
});
// UNTIL https://github.com/Agoric/agoric-sdk/pull/8559 is merged
// Move bundles from submission subdir to submission path.
execSync(`mv ${submissionPath}/.agoric/cache/* ${submissionPath}`);
}
};

export const buildTestImages = (proposals: ProposalInfo[], dry = false) => {
for (const proposal of proposals) {
if (!dry) {
console.log(
`\nBuilding test image for proposal ${proposal.proposalName}`,
);
}
const { name, target } = imageNameForProposal(proposal, 'test');
// 'load' to ensure the images are output to the Docker client. Seems to be necessary
// for the CI docker/build-push-action to re-use the cached stages.
const cmd = `docker buildx build --load --tag ${name} --target ${target} .`;
console.log(cmd);
if (!dry) {
// `time` to output how long each build takes
execSync(`time ${cmd}`, { stdio: 'inherit' });
}
}
};
Loading
Loading