diff --git a/.github/deploy-ipfs.mjs b/.github/deploy-ipfs.mjs new file mode 100644 index 0000000000..9ff6190713 --- /dev/null +++ b/.github/deploy-ipfs.mjs @@ -0,0 +1,50 @@ +import { readdir, readFile } from 'node:fs/promises' +import { join, relative, sep } from 'node:path' +import { Blob } from 'node:buffer' + +function formatBytes(bytes) { + const sizes = 'kmgt' + const i = Math.min(parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10), sizes.length - 1) + return `${Math.round(bytes / Math.pow(1024, i), 2)}${sizes.charAt(i - 1)}B` +} + +async function* readAllFilesRecursively(root) { + for (const entry of await readdir(root, { withFileTypes: true })) { + const fullPath = join(root, entry.name) + if (entry.isDirectory()) { + yield* readAllFilesRecursively(fullPath) + } else if (entry.isFile()) { + yield fullPath + } + } +} + +const pinDirectoryToPinata = async (root) => { + if (!root) throw new Error(`Usage: node pin-ens.mjs `) + + const formData = new FormData() + + for await (const file of readAllFilesRecursively(root)) { + const normalizedPath = relative(root, file).split(sep).join('/') + const buffer = await readFile(file) + const blob = new Blob([buffer]) + formData.append('file', blob, normalizedPath) + console.info(`Added file: ${normalizedPath} (${formatBytes(buffer.length)})`) + } + + if (!process.env.PINATA_JWT) throw new Error(`PINATA_JWT environment variable is not set, cannot upload.`) + + const response = await fetch('https://api.pinata.cloud/pinning/pinFileToIPFS', { + method: 'POST', + headers: { Authorization: 'Bearer ' + process.env.PINATA_JWT }, + body: formData, + }) + const text = await response.text() + if (!response.ok) throw new Error(`Upload failed: ${response.status} ${response.statusText}\n${text}`) + console.info(text) +} + +pinDirectoryToPinata(process.argv[2]).catch((error) => { + console.error(error) + process.exitCode = 1 +}) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 89cdd5f129..9252e4bcfd 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -111,6 +111,7 @@ jobs: name: Cypress e2e tests in ${{ matrix.browser }} ${{ matrix.count }} timeout-minutes: 15 runs-on: ubuntu-latest + if: github.ref_name != 'feat/ens' steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -159,3 +160,22 @@ jobs: - name: Check runtime errors if: always() run: if grep --ignore-case --extended-regexp "update depth exceeded|many re-renders|unmounted component|non-unique keys|uncontrolled to controlled|properties of undefined" e2e-*.log; then exit 1; fi + + deploy-ipfs: + name: Deploy to IPFS + if: github.ref_name == 'main' + timeout-minutes: 10 + runs-on: ubuntu-latest + environment: ens + needs: [lint, test, cypress-component, cypress-component-rpc, cypress-e2e] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: yarn + - run: yarn set version stable + - run: yarn install --immutable + - run: yarn build + - name: Deploy to IPFS via Pinata + run: yarn deploy:ipfs diff --git a/.github/workflows/ipfs.yaml b/.github/workflows/ipfs.yaml new file mode 100644 index 0000000000..3f825a25fa --- /dev/null +++ b/.github/workflows/ipfs.yaml @@ -0,0 +1,27 @@ +name: IPFS +on: [push] +env: + DO_NOT_TRACK: 1 + IBM_TELEMETRY_DISABLED: true +permissions: + contents: read +jobs: + deploy-ipfs: + name: Deploy to IPFS + if: github.ref_name == 'feat/ens' + timeout-minutes: 10 + runs-on: ubuntu-latest + environment: ens + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: yarn + - run: yarn set version stable + - run: yarn install --immutable + - run: yarn build + - name: Deploy to IPFS via Pinata + run: yarn deploy:ipfs + env: + PINATA_JWT: ${{ secrets.PINATA_JWT }} diff --git a/package.json b/package.json index c2bffa0f60..32c08bff03 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "format:check": "prettier --check \"**/*.{ts,tsx,md}\"", "prepare": "husky", "storybook": "yarn workspace curve-ui-kit run storybook", - "storybook:build": "yarn workspace curve-ui-kit run build:storybook" + "storybook:build": "yarn workspace curve-ui-kit run build:storybook", + "deploy:ipfs": "node .github/deploy-ipfs.mjs ./apps/main/dist" }, "devDependencies": { "@commitlint/cli": "^20.1.0",