Why?
Should I commit the build directory?
If you ever worked with Truffle, I bet you asked yourself this question at least once.
There are different currents of thought between developers but there are a few unavoidable side effects in committing the build directory:
- the
updatedAt
field is updated every time a contract is compiled - some user-specific
absolute paths
are stored inside every artifact and may cause problems when multiple persons are working on the same codebase -
git diffs
become much more difficult and messy to read
But Truffle artifacts also contain the addresses of deployed contracts for each network and these are crucial in order for migrations to work properly.
The solution is to store the addresses in separate files and commit them instead of the build directory.
Later on, another developer working on the same codebase could just clone the repo, compile the contracts and merge the deployment addresses back into the artifacts, thus restoring a clean and working state for Truffle.
Installation
npm install --save-dev abi-deployments
Usage
- Export: deployments are read from Truffle artifacts and stored into separate network-specific JSON files.
- Import: previously exported deployments are merged back into Truffle artifacts.
The most common usage is through Command Line Interface but a Programmable API is available as well.
Command Line Interface
Export deployments
The export command will scan the artifactsDir
and collect info about the
deployments that were made on different networks for each contract. Then it will
store the deployments in JSON files inside the networksDir
, one for each
network.
truffle-deployments export [artifactsDir] [networksDir]
Option | Description |
---|---|
--network <network>, -n |
specify network/s to export (e.g. 1 or 1,4) |
--reset, -r |
delete old exported deployments |
If not specified, artifactsDir
defaults to build/contracts
and networksDir
defaults to networks
.
If a network file already exists, by default Truffle Deployments will append new
deployments without deleting the old ones with the exception of conflicting
contracts that will be overwritten. To delete the old deployments consider using
the --reset
option.
Consider this initial state:
// build/contracts/Token.json
{
"contractName": "Token",
"abi": [],
"bytecode": "0x60806040523480156200001157600080fd5b50604"
"networks": {
"1": {
"events": {},
"links": {},
"address": "0xefE1e4e13F9ED8399eE8e258b3a1717b7D15f054",
"transactionHash": "0x35db37ae85e2d4af8fb6fc83f1e6edf5ade8700cf75e19dc3f1a0307768948c7"
},
"4": {
"events": {},
"links": {},
"address": "0xb56c770c2fa5222947a9e3c5beb8dc46dd656b5f",
"transactionHash": "0xe31509629b75866917ab387751a75b737b973622d9765af69b557bde038e1210"
}
}
}
Running the export
command will generate the following network files inside
the networksDir
:
networks/
1.json
4.json
Each network file contains all exported deployments:
// networks/1.json
[
{
"contract": "Token",
"address": "0xefE1e4e13F9ED8399eE8e258b3a1717b7D15f054",
"transactionHash": "0x35db37ae85e2d4af8fb6fc83f1e6edf5ade8700cf75e19dc3f1a0307768948c7"
}
]
// networks/4.json
[
{
"contract": "Token",
"address": "0xb56c770c2fa5222947a9e3c5beb8dc46dd656b5f",
"transactionHash": "0xe31509629b75866917ab387751a75b737b973622d9765af69b557bde038e1210"
}
]
Import deployments
The import command will scan all the exported deployments inside the
networksDir
and merge them into respective contract artifact in the
artifactsDir
.
truffle-deployments import [networksDir] [artifactsDir]
Option | Description |
---|---|
--network <network>, -n |
specify network/s to import (e.g. 1 or 1,4) |
If not specified, artifactsDir
defaults to build/contracts
and networksDir
defaults to networks
.
Consider this initial state:
// networks/4.json
[
{
"contract": "Token",
"address": "0xb56c770c2fa5222947a9e3c5beb8dc46dd656b5f",
"transactionHash": "0xe31509629b75866917ab387751a75b737b973622d9765af69b557bde038e1210"
}
]
// build/contracts/Token.json
{
"contractName": "Token",
"abi": [],
"bytecode": "0x60806040523480156200001157600080fd5b50604"
"networks": {
"1": {
"events": {},
"links": {},
"address": "0xefE1e4e13F9ED8399eE8e258b3a1717b7D15f054",
"transactionHash": "0x35db37ae85e2d4af8fb6fc83f1e6edf5ade8700cf75e19dc3f1a0307768948c7"
}
}
}
Running the import
command will update build/contracts/Token.json
like this:
// build/contracts/Token.json
{
"contractName": "Token",
"abi": [],
"bytecode": "0x60806040523480156200001157600080fd5b50604"
"networks": {
"1": {
"events": {},
"links": {},
"address": "0xefE1e4e13F9ED8399eE8e258b3a1717b7D15f054",
"transactionHash": "0x35db37ae85e2d4af8fb6fc83f1e6edf5ade8700cf75e19dc3f1a0307768948c7"
},
"4": {
"events": {},
"links": {},
"address": "0xb56c770c2fa5222947a9e3c5beb8dc46dd656b5f",
"transactionHash": "0xe31509629b75866917ab387751a75b737b973622d9765af69b557bde038e1210"
}
}
}
Programmable API
Beside the Command Line Interface, Truffle Deployments can also be used programmatically.
Export deployments
const truffleDeployments = require('truffle-deployments');
const artifactsDir = 'build/contracts';
const networksDir = 'networks';
const options = { networks: [4], reset: true };
truffleDeployments.export(artifactsDir, networksDir, options);
Import deployments
const truffleDeployments = require('truffle-deployments');
const artifactsDir = 'build/contracts';
const networksDir = 'networks';
const options = { networks: [4] };
truffleDeployments.import(networksDir, artifactsDir, options);