-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move the contracts and app deployments into the same workflow (#107)
- Move the contracts and app deployment into the same workflow (makes it easier to share data and execute sequentially). - Write a “deployment context” file whenever ./deploy gets executed successfully. - Add a script that converts this file into the env vars needed by Next.js. - Update the workflows wording to make it more concise & consistent.
- Loading branch information
Showing
9 changed files
with
263 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
name: Testnet Deployment | ||
|
||
# This workflow: | ||
# - Deploys the contracts to the Liquity v2 Testnet (currently disabled) | ||
# - Deploys the app to Vercel (only for the main branch, not PRs) | ||
|
||
on: | ||
push: | ||
branches: [main] | ||
paths: | ||
- ".github/workflows/deploy-testnet.yml" | ||
- "contracts/**" | ||
- "frontend/**" | ||
pull_request: | ||
paths: | ||
- ".github/workflows/deploy-testnet.yml" | ||
- "contracts/**" | ||
|
||
env: | ||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} | ||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} | ||
|
||
concurrency: | ||
group: ${{ github.workflow }}-${{ github.ref }} | ||
cancel-in-progress: true | ||
|
||
jobs: | ||
deploy-contracts: | ||
name: Deploy contracts | ||
if: false # Disable contracts deployment for now | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Git checkout | ||
uses: actions/checkout@v4 | ||
with: | ||
submodules: recursive | ||
|
||
- name: Install pnpm | ||
uses: pnpm/action-setup@v3.0.0 | ||
with: | ||
version: 8 | ||
|
||
- name: Install Node.js | ||
uses: actions/setup-node@v4 | ||
with: | ||
node-version-file: '.node-version' | ||
cache: 'pnpm' | ||
cache-dependency-path: 'contracts/pnpm-lock.yaml' | ||
|
||
- name: Install dependencies | ||
run: pnpm install | ||
|
||
- name: Install Foundry | ||
uses: foundry-rs/foundry-toolchain@v1 | ||
with: | ||
version: nightly | ||
|
||
- name: Run deployment tool | ||
working-directory: ./contracts | ||
run: ./deploy liquity-testnet --verify | ||
env: | ||
DEPLOYER: ${{ secrets.DEPLOYER }} | ||
|
||
- name: Upload deployment context | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: deployment-context | ||
path: ./contracts/deployment-context-latest.json | ||
|
||
deploy-app: | ||
name: Deploy app | ||
runs-on: ubuntu-latest | ||
if: ${{ github.event_name != 'pull_request' }} | ||
steps: | ||
- name: Git checkout | ||
uses: actions/checkout@v4 | ||
|
||
- name: Install pnpm | ||
uses: pnpm/action-setup@v3.0.0 | ||
with: | ||
version: 8 | ||
|
||
- name: Install Vercel CLI | ||
run: pnpm install --global vercel@canary | ||
|
||
- name: Download deployment context | ||
if: false # Disable contracts deployment for now | ||
uses: actions/download-artifact@v4 | ||
with: | ||
name: deployment-context | ||
|
||
- name: Pull Vercel Environment Information | ||
run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} | ||
|
||
- name: Build Project Artifacts | ||
run: | | ||
test -f ./deployment-context-latest.json && cat ./deployment-context-latest.json | pn tsx contracts/utils/deployment-artifacts-to-next-env.ts > ./frontend/.env.local | ||
vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} | ||
- name: Deploy Project Artifacts to Vercel | ||
run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,6 +44,7 @@ | |
"tsx": "^4.7.1", | ||
"typechain": "^8.1.0", | ||
"typescript": ">=4.5.0", | ||
"zod": "^3.22.4", | ||
"zx": "^7.2.3" | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
import { z } from "zod"; | ||
import { argv, echo, stdin } from "zx"; | ||
|
||
const HELP = ` | ||
converts the deployment artifacts created by ./deploy into environment | ||
variables to be used by the Next.js app located in frontend/. | ||
Usage: | ||
./deployment-artifacts-to-app-env.ts < deployment-latest.json | ||
Options: | ||
--help, -h Show this help message. | ||
`; | ||
|
||
const ZAddress = z.string().regex(/^0x[0-9a-fA-F]{40}$/); | ||
|
||
const ZDeploymentContext = z.object({ | ||
options: z.object({ | ||
chainId: z.number(), | ||
deployer: z.string(), // can be an address or a private key | ||
help: z.boolean(), | ||
openDemoTroves: z.boolean(), | ||
rpcUrl: z.string(), | ||
verify: z.boolean(), | ||
verifier: z.string(), | ||
}), | ||
deployedContracts: z.record(ZAddress), | ||
}); | ||
|
||
type DeploymentContext = z.infer<typeof ZDeploymentContext>; | ||
|
||
const NULL_ADDRESS = `0x${"0".repeat(40)}`; | ||
|
||
export async function main() { | ||
if ("help" in argv || "h" in argv) { | ||
echo`${HELP}`; | ||
process.exit(0); | ||
} | ||
|
||
const deploymentContext = parseDeploymentContext(await stdin()); | ||
|
||
console.log( | ||
objectToEnvironmentVariables( | ||
deploymentContextToAppEnvVariables(deploymentContext), | ||
), | ||
); | ||
} | ||
|
||
function objectToEnvironmentVariables(object: Record<string, unknown>) { | ||
return Object.entries(object) | ||
.map(([key, value]) => `${key}=${value}`) | ||
.sort() | ||
.join("\n"); | ||
} | ||
|
||
function deploymentContextToAppEnvVariables({ deployedContracts, options }: DeploymentContext) { | ||
const appEnvVariables: Record<string, string> = { | ||
NEXT_PUBLIC_CHAIN_ID: String(options.chainId), | ||
}; | ||
|
||
for (const [contractName, address] of Object.entries(deployedContracts)) { | ||
const envVarName = contractNameToAppEnvVariable(contractName); | ||
if (envVarName) { | ||
appEnvVariables[envVarName] = address; | ||
} | ||
} | ||
|
||
appEnvVariables.NEXT_PUBLIC_CONTRACT_FUNCTION_CALLER = NULL_ADDRESS; | ||
appEnvVariables.NEXT_PUBLIC_CONTRACT_HINT_HELPERS = NULL_ADDRESS; | ||
|
||
return appEnvVariables; | ||
} | ||
|
||
function contractNameToAppEnvVariable(contractName: string) { | ||
switch (contractName) { | ||
case "ActivePool": | ||
return "NEXT_PUBLIC_CONTRACT_ACTIVE_POOL"; | ||
case "BoldToken": | ||
return "NEXT_PUBLIC_CONTRACT_BOLD_TOKEN"; | ||
case "BorrowerOperations": | ||
return "NEXT_PUBLIC_CONTRACT_BORROWER_OPERATIONS"; | ||
case "CollSurplusPool": | ||
return "NEXT_PUBLIC_CONTRACT_COLL_SURPLUS_POOL"; | ||
case "DefaultPool": | ||
return "NEXT_PUBLIC_CONTRACT_DEFAULT_POOL"; | ||
case "GasPool": | ||
return "NEXT_PUBLIC_CONTRACT_GAS_POOL"; | ||
case "PriceFeedTestnet": | ||
return "NEXT_PUBLIC_CONTRACT_PRICE_FEED_TESTNET"; | ||
case "SortedTroves": | ||
return "NEXT_PUBLIC_CONTRACT_SORTED_TROVES"; | ||
case "StabilityPool": | ||
return "NEXT_PUBLIC_CONTRACT_STABILITY_POOL"; | ||
case "TroveManager": | ||
return "NEXT_PUBLIC_CONTRACT_TROVE_MANAGER"; | ||
} | ||
return null; | ||
} | ||
|
||
function parseDeploymentContext(content: string) { | ||
if (!content.trim()) { | ||
console.error("\nNo deployment context provided.\n"); | ||
process.exit(1); | ||
} | ||
|
||
let json: unknown; | ||
try { | ||
json = JSON.parse(content); | ||
} catch (error) { | ||
console.error("\nInvalid format provided.\n"); | ||
process.exit(1); | ||
} | ||
|
||
const context = ZDeploymentContext.safeParse(json); | ||
if (!context.success) { | ||
console.error("\nInvalid deployment context provided.\n"); | ||
console.error( | ||
context.error.errors.map((error) => { | ||
return `${error.path.join(".")}: ${error.message} (${error.code})`; | ||
}).join("\n"), | ||
); | ||
console.error(""); | ||
process.exit(1); | ||
} | ||
|
||
return context.data; | ||
} | ||
|
||
main(); |
Oops, something went wrong.