Skip to content

Commit 100a098

Browse files
authored
Merge pull request #482 from JoinColony/feature/extensions-versions
Introduce Extension Versioning
2 parents e2f1e1c + 6643f1d commit 100a098

File tree

92 files changed

+83212
-6736
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+83212
-6736
lines changed

README.md

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,18 +154,14 @@ Done 🎊
154154

155155
### To upgrade to a new colonyNetwork version
156156

157-
1) Add the version to `constants.ts` in `ColonyVersion`
158-
2) Change the `CurrentVersion` variable to the one you just added
157+
1) Add the version to `versions.ts` in `ColonyVersion` as well as the network git tag to `releaseMaps`
159158
3) Add the git tag to `src/constants.ts` release map
160159
4) _Optional:_ If you are tracking a development branch instead of a static tag or commit, make sure to pull the latest changes, otherwise the contracts generated will be exactly the same as your last ones -- _this is a step often forgotten when using a dev version_
161160
5) If needed: add new contracts that need clients to the `contractsToBuild` array in `scripts/build-contracts.ts`
162161
6) Run
163162
```shell
164-
DISABLE_DOCKER=true npm run build-contracts -- -V=X
163+
npm run build-contracts
165164
```
166-
167-
where `X` is the version number you just added (the incremental integer of the `ColonyVersion` enum).
168-
169165
This will create a new folder: `src/contracts/X` containing all the type definitions you'll need to implement the new colony client.
170166

171167
7) Update the following lines in `ColonyNetworkClient.ts` to reflect the new version:
@@ -178,6 +174,18 @@ import { IColonyNetwork } from '../contracts/X/IColonyNetwork';
178174
8) Update all the other contract imports in the non-colony clients, even if they haven't been upgraded (just in case). Then make adjustments to the clients to reflect the contract changes (typescript will tell you, where to make changes). Also add necessary helper functions (e.g. `withProofs` functions) for newly added methods. The newly added methods and their required roles can be found in [this file](https://github.com/JoinColony/colonyNetwork/blob/develop/contracts/colony/ColonyAuthority.sol) (and by diffing the generated interface files).
179175

180176

177+
### To add new extension contract versions:
178+
1. Add the new version and corresponding git tag for one or more extesions inside `versions.ts`
179+
2. Run `npm run build-contracts` _-- this will build the network contracts for the extensions using `typechain`_
180+
3. Run `npm run build-clients` _-- this will build basic clients and addon files for your new extension versions_
181+
4. If you need extra methods added to your client _(helpers like `withProofs`)_, add them inside the `Addon` file that you'll find in the client's folder _(don't forget to also add the estimate method)_
182+
183+
Eg:
184+
```js
185+
'/src/clients/Extensions/OneTxPayment/1/OneTxPaymentClient.ts' // the OneTxPayment extension client
186+
'/src/clients/Extensions/OneTxPayment/1/OneTxPaymentClientAddons.ts' // the OneTxPayment extension client addons
187+
```
188+
181189
## License
182190

183191
GPL-3.0

package-lock.json

Lines changed: 32 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@colony/colony-js",
3-
"version": "3.1.2",
3+
"version": "v4.0.0",
44
"main": "lib/index.js",
55
"module": "lib-esm/index.js",
66
"license": "GPL-3.0-only",
@@ -14,7 +14,9 @@
1414
"compile-esm": "tsc -p tsconfig.build.json -m es6 --outDir lib-esm",
1515
"copy-declarations": "copyfiles -u 1 src/contracts/**/*.d.ts lib && copyfiles -u 1 src/contracts/**/*.d.ts lib-esm",
1616
"build-docs": "typedoc --out docs src/index.ts",
17-
"build-contracts": "ts-node -P scripts/tsconfig-scripts.json scripts/build-contracts.ts",
17+
"build-contracts": "DISABLE_DOCKER=true npm run build-contracts:docker",
18+
"build-contracts:docker": "ts-node -P scripts/tsconfig-scripts.json scripts/build-contracts.ts",
19+
"build-clients": "ts-node -P scripts/tsconfig-scripts.json scripts/build-clients.ts",
1820
"prepublishOnly": "npm test && npm run build"
1921
},
2022
"devDependencies": {
@@ -26,6 +28,7 @@
2628
"@types/yargs": "^15.0.4",
2729
"@typescript-eslint/eslint-plugin": "^2.24.0",
2830
"@typescript-eslint/parser": "^2.24.0",
31+
"camelcase": "^6.2.0",
2932
"copyfiles": "^2.2.0",
3033
"eslint": "^6.8.0",
3134
"eslint-config-airbnb-base": "^14.1.0",

scripts/build-clients.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* - Get clients and versions
3+
* - Check if they exist
4+
* - Generate client for version
5+
*/
6+
import { resolve as resolvePath } from 'path';
7+
import { existsSync, mkdirSync, writeFileSync } from 'fs';
8+
9+
import { Extension } from '../src/clients/Extensions/colonyContractExtensions';
10+
import {
11+
CurrentCoinMachineVersion,
12+
CurrentOneTxPaymentVersion,
13+
CurrentVotingReputationVersion,
14+
} from '../src/versions';
15+
import getClientTemplate from './client-templates/extension-client-generator';
16+
import getClientAddonTemplate from './client-templates/extension-client-addons-generator';
17+
18+
const extensionContracts = [
19+
Extension.OneTxPayment,
20+
Extension.CoinMachine,
21+
Extension.VotingReputation,
22+
];
23+
24+
const currentExtensionsVersions = {
25+
[Extension.OneTxPayment]: CurrentOneTxPaymentVersion,
26+
[Extension.CoinMachine]: CurrentCoinMachineVersion,
27+
[Extension.VotingReputation]: CurrentVotingReputationVersion,
28+
};
29+
30+
const getExtensionVersionedPath = (
31+
extensionName: Extension,
32+
extensionVersion: number,
33+
): string =>
34+
resolvePath(
35+
__dirname,
36+
'../src/clients/Extensions',
37+
extensionName,
38+
String(extensionVersion),
39+
);
40+
41+
const checkClientVersionExistance = (
42+
extensionName: Extension,
43+
extensionVersion: number,
44+
): boolean => {
45+
const extensionPath = getExtensionVersionedPath(
46+
extensionName,
47+
extensionVersion,
48+
);
49+
return existsSync(`${extensionPath}/${extensionName}Client.ts`);
50+
};
51+
52+
const generateExtensionClient = async (
53+
extensionName: Extension,
54+
extensionVersion: number,
55+
): Promise<void> => {
56+
const extensionPath = getExtensionVersionedPath(
57+
extensionName,
58+
extensionVersion,
59+
);
60+
const client = getClientTemplate(extensionName, extensionVersion);
61+
const addons = getClientAddonTemplate(extensionName, extensionVersion);
62+
63+
mkdirSync(extensionPath, { recursive: true });
64+
65+
writeFileSync(`${extensionPath}/${extensionName}Client.ts`, client, {
66+
encoding: 'utf8',
67+
});
68+
writeFileSync(`${extensionPath}/${extensionName}ClientAddons.ts`, addons, {
69+
encoding: 'utf8',
70+
});
71+
};
72+
73+
const orchestrateBuild = async (): Promise<void> => {
74+
await Promise.all(
75+
extensionContracts.map(async (extensionContract) => {
76+
const extensionVersion = currentExtensionsVersions[extensionContract];
77+
const clientExists = checkClientVersionExistance(
78+
extensionContract,
79+
extensionVersion,
80+
);
81+
82+
if (!clientExists) {
83+
await generateExtensionClient(extensionContract, extensionVersion);
84+
}
85+
}),
86+
);
87+
};
88+
89+
orchestrateBuild();

scripts/build-contracts.ts

Lines changed: 81 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
import { resolve as resolvePath } from 'path';
22
import { copyFileSync } from 'fs';
33
import { promisify } from 'util';
4-
5-
import { options } from 'yargs';
4+
import * as camelcase from 'camelcase';
65
import * as execute from 'execa';
76
import * as rimraf from 'rimraf';
87

9-
import { ColonyVersion, CurrentVersion, releaseMap } from '../src/constants';
8+
import {
9+
CurrentColonyVersion,
10+
releaseMap,
11+
CurrentCoinMachineVersion,
12+
CurrentOneTxPaymentVersion,
13+
CurrentVotingReputationVersion,
14+
} from '../src/versions';
15+
import { Extension } from '../src/clients/Extensions/colonyContractExtensions';
16+
17+
/*
18+
* State Vars
19+
*/
20+
let currentNetworkTag: string;
1021

1122
const rimrafPromise = promisify(rimraf);
1223

@@ -19,31 +30,38 @@ const vendorTokenDir = resolvePath(__dirname, '../vendor/tokens');
1930

2031
const contractsToBuild = ['IColony', 'IColonyNetwork', 'TokenLocking'];
2132

22-
const extensionContracts = ['OneTxPayment', 'CoinMachine'];
33+
const extensionContracts = [
34+
Extension.OneTxPayment,
35+
Extension.CoinMachine,
36+
Extension.VotingReputation,
37+
];
38+
39+
const currentExtensionsVersions = {
40+
[Extension.OneTxPayment]: CurrentOneTxPaymentVersion,
41+
[Extension.CoinMachine]: CurrentCoinMachineVersion,
42+
[Extension.VotingReputation]: CurrentVotingReputationVersion,
43+
};
2344

2445
const tokenContracts = [
2546
// ERC20 tokens
2647
'Token',
2748
'TokenERC20',
2849
'TokenSAI',
2950
];
30-
31-
const args = options({
32-
V: { type: 'number', alias: 'contract-version', demandOption: true },
33-
}).argv;
34-
35-
const version = args.V as ColonyVersion;
51+
const version = CurrentColonyVersion;
3652
const outRoot = resolvePath(__dirname, '../src/contracts');
37-
const outDir = `${outRoot}/${version}`;
53+
const colonyContractsOutDir = `${outRoot}/colony/${version}`;
3854
const deployDir = `${outRoot}/deploy`;
3955

40-
if (!releaseMap[version]) {
41-
throw new Error(`Version ${version} of colonyNetwork doesn't seem to exist`);
42-
}
56+
const provisionNetworkVendor = async (tag: string): Promise<void> => {
57+
if (!tag) {
58+
throw new Error(
59+
`Version ${version} of colonyNetwork doesn't seem to exist`,
60+
);
61+
}
4362

44-
const buildContracts = async (): Promise<void> => {
45-
console.info(`Checking out network tag ${releaseMap[version]}`);
46-
const git = execute('git', ['checkout', releaseMap[version]], {
63+
console.info(`Checking out network tag ${tag}`);
64+
const git = execute('git', ['checkout', tag], {
4765
cwd: networkDir,
4866
});
4967
if (git.stdout) git.stdout.pipe(process.stdout);
@@ -68,23 +86,19 @@ const buildContracts = async (): Promise<void> => {
6886
});
6987
if (truffle.stdout) truffle.stdout.pipe(process.stdout);
7088
await truffle;
89+
};
7190

72-
if (version === CurrentVersion) {
73-
// Copy contract json files of latest version for deployment purposes
74-
copyFileSync(`${tokenBuildDir}/Token.json`, `${deployDir}/Token.json`);
75-
copyFileSync(
76-
`${tokenBuildDir}/TokenAuthority.json`,
77-
`${deployDir}/TokenAuthority.json`,
78-
);
79-
80-
/*
81-
* Add extensions contracts to be built
82-
*/
83-
contractsToBuild.push(...extensionContracts);
91+
const buildColonyContracts = async (): Promise<void> => {
92+
// @ts-ignore
93+
const releaseTag: string = releaseMap.colony[version];
8494

85-
// Just build token contracts for the latest version
86-
contractsToBuild.push(...tokenContracts);
95+
if (currentNetworkTag !== releaseTag) {
96+
await provisionNetworkVendor(releaseTag);
97+
currentNetworkTag = releaseTag;
8798
}
99+
100+
// Just build token contracts for the latest version
101+
contractsToBuild.push(...tokenContracts);
88102
const contractGlobs = `{${contractsToBuild
89103
.map((c) => `${c}.json`)
90104
.join(',')}}`;
@@ -93,11 +107,45 @@ const buildContracts = async (): Promise<void> => {
93107
'--target',
94108
'ethers-v4',
95109
'--outDir',
96-
outDir,
110+
colonyContractsOutDir,
97111
`{${networkDir}/{${relativeBuildDir},${relativeTokenDir}}/${contractGlobs},${vendorTokenDir}/${contractGlobs}}`,
98112
]);
99113
if (typechain.stdout) typechain.stdout.pipe(process.stdout);
100114
await typechain;
101115
};
102116

103-
buildContracts();
117+
const buildExtensionContracts = async (): Promise<void> => {
118+
await Promise.all(
119+
extensionContracts.map(async (extensionContract) => {
120+
const extensionVersion = currentExtensionsVersions[extensionContract];
121+
const releaseTag: string =
122+
// @ts-ignore
123+
releaseMap.extension[camelcase(extensionContract)][extensionVersion];
124+
125+
if (currentNetworkTag !== releaseTag) {
126+
await provisionNetworkVendor(releaseTag);
127+
currentNetworkTag = releaseTag;
128+
}
129+
130+
const extensionOutDir = `${outRoot}/extensions/${camelcase(
131+
extensionContract,
132+
)}/${currentExtensionsVersions[extensionContract]}`;
133+
const typechain = execute('typechain', [
134+
'--target',
135+
'ethers-v4',
136+
'--outDir',
137+
extensionOutDir,
138+
`${networkDir}/${relativeBuildDir}/${extensionContract}.json`,
139+
]);
140+
if (typechain.stdout) typechain.stdout.pipe(process.stdout);
141+
await typechain;
142+
}),
143+
);
144+
};
145+
146+
const orchestrateBuild = async (): Promise<void> => {
147+
await buildColonyContracts();
148+
await buildExtensionContracts();
149+
};
150+
151+
orchestrateBuild();

0 commit comments

Comments
 (0)