diff --git a/.github/workflows/bundle-deploy-eas-update.yml b/.github/workflows/bundle-deploy-eas-update.yml new file mode 100644 index 00000000..72a38eaa --- /dev/null +++ b/.github/workflows/bundle-deploy-eas-update.yml @@ -0,0 +1,55 @@ +--- +name: Bundle and Deploy EAS Update + +on: + workflow_dispatch: + inputs: + runtimeVersion: + type: string + description: Runtime version (in x.x.x format) that this update is for + required: true + +jobs: + bundleDeploy: + name: Bundle and Deploy EAS Update + runs-on: ubuntu-latest + steps: + - name: 🧐 Validate version + run: | + [[ "${{ github.event.inputs.runtimeVersion }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && echo "Version is valid" || exit 1 + + - name: ⬇️ Checkout + uses: actions/checkout@v4 + + - name: 🔧 Setup Node + uses: actions/setup-node@v4 + with: + node-version-file: .nvmrc + cache: yarn + + - name: ⚙️ Install Dependencies + run: yarn install + + - name: 🪛 Install jq + uses: dcarbone/install-jq-action@v2 + + - name: ⛏️ Setup Expo + run: yarn global add eas-cli-local-build-plugin + + - name: 🔤 Compile Translations + run: yarn intl:build + + - name: ✏️ Write environment variables + run: | + export json='${{ secrets.GOOGLE_SERVICES_TOKEN }}' + echo "${{ secrets.ENV_TOKEN }}" > .env + echo "$json" > google-services.json + + - name: 🏗️ Create Bundle + run: yarn export + + - name: 📦 Package Bundle and 🚀 Deploy + run: yarn make-deploy-bundle + env: + DENIS_API_KEY: ${{ secrets.DENIS_API_KEY }} + RUNTIME_VERSION: ${{ github.event.inputs.runtimeVersion }} diff --git a/code-signing/certificate.pem b/code-signing/certificate.pem new file mode 100644 index 00000000..bfc5cdbd --- /dev/null +++ b/code-signing/certificate.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC0TCCAbmgAwIBAgIJcMN2yt5KNDqTMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV +BAMTB0JsdWVza3kwHhcNMjQwMzE0MDA1OTU4WhcNMzQwMzE0MDA1OTU4WjASMRAw +DgYDVQQDEwdCbHVlc2t5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +izSAWEc3wRoa3eTBEh/kE9pH0d6jhEGw9GrYfei60MHT1pSq2cTdyUM1yUZchAeW +gFFtqFxX0pfIZQyMlIZbjkaOxOqzWhB0aCsxngnhbSahFwRxkVwTAuonhqIpaLBL +hrCCCQ2IfZUpy8QeasqlTlmvmijuCC34fXxJlxNcj8SqzIZi+civ7U5PMPfIMMnD +tCDIBy1vxMk57m25X2ikcWUFW64qNVLkFAL36xEnmFTL4Ivqpz23gUcUIe1zbesY +jAgDtlwnAE7mU3oagCUDcSuOveT4POhT35Xp3Y/07I68kmXtrPxwd5k0L0zbisEm +poKZ87E2X29BitihicMpBwIDAQABoyowKDAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0l +AQH/BAwwCgYIKwYBBQUHAwMwDQYJKoZIhvcNAQELBQADggEBAED1gdMF0yr8Gy87 +RgyaeVpPySwSsO0selmXXrcmOWgiPA05lubyhFEa4P5kdzBEByG2MT+pJkjGYpvK +XRnqXM5VvdS2RhYYFH0cFOIUqBKwCnzViCMuGQeoGUx4oPcKFS0PQ1WjW2d4pS75 +51GBfB6LOepsCHUG0A9XEk7EAyUWc4M2ITCJsTtJh8CVn2pTks2q14ETDs86YQv4 +peDaJv8nhIe8oQkeGn2o/P/ctkwJg/uBydQUsWgjjGTQZTilVjGTW1mwDr9FucAE +d5gKIk4rtR/3Zd/NDdqp8PrkoWeVM7Hwr789/mpUOeqa/j7YNkDYQh7x+M/odd1D +KY0bQEQ= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/package.json b/package.json index b526825f..bc2b62ec 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,9 @@ "intl:extract": "lingui extract", "intl:compile": "lingui compile", "nuke": "rm -rf ./node_modules && rm -rf ./ios && rm -rf ./android", - "update-extensions": "scripts/updateExtensions.sh" + "update-extensions": "bash scripts/updateExtensions.sh", + "export": "npx expo export", + "make-deploy-bundle": "bash scripts/bundleUpdate.sh" }, "dependencies": { "@atproto/api": "^0.12.0", diff --git a/scripts/bundleUpdate.js b/scripts/bundleUpdate.js new file mode 100644 index 00000000..00217dcd --- /dev/null +++ b/scripts/bundleUpdate.js @@ -0,0 +1,104 @@ +const crypto = require('crypto') +const fs = require('fs') +const fsp = fs.promises +const path = require('path') + +const DIST_DIR = './dist' +const BUNDLES_DIR = '/_expo/static/js' +const IOS_BUNDLE_DIR = path.join(DIST_DIR, BUNDLES_DIR, '/ios') +const ANDROID_BUNDLE_DIR = path.join(DIST_DIR, BUNDLES_DIR, '/android') +const METADATA_PATH = path.join(DIST_DIR, '/metadata.json') +const DEST_DIR = './bundleTempDir' + +// Weird, don't feel like figuring out _why_ it wants this +const METADATA = require(`../${METADATA_PATH}`) +const IOS_METADATA_ASSETS = METADATA.fileMetadata.ios.assets +const ANDROID_METADATA_ASSETS = METADATA.fileMetadata.android.assets + +const getMd5 = async path => { + return new Promise(res => { + const hash = crypto.createHash('md5') + const rStream = fs.createReadStream(path) + rStream.on('data', data => { + hash.update(data) + }) + rStream.on('end', () => { + res(hash.digest('hex')) + }) + }) +} + +const moveFiles = async () => { + console.log('Making directory...') + await fsp.mkdir(DEST_DIR) + await fsp.mkdir(path.join(DEST_DIR, '/assets')) + + console.log('Getting ios md5...') + const iosCurrPath = path.join( + IOS_BUNDLE_DIR, + (await fsp.readdir(IOS_BUNDLE_DIR))[0], + ) + const iosMd5 = await getMd5(iosCurrPath) + const iosNewPath = `bundles/${iosMd5}.bundle` + + console.log('Copying ios bundle...') + await fsp.cp(iosCurrPath, path.join(DEST_DIR, iosNewPath)) + + console.log('Getting android md5...') + const androidCurrPath = path.join( + ANDROID_BUNDLE_DIR, + (await fsp.readdir(ANDROID_BUNDLE_DIR))[0], + ) + const androidMd5 = await getMd5(androidCurrPath) + const androidNewPath = `bundles/${androidMd5}.bundle` + + console.log('Copying android bundle...') + await fsp.cp(androidCurrPath, path.join(DEST_DIR, androidNewPath)) + + const iosAssets = [] + const androidAssets = [] + + console.log('Getting ios asset md5s and moving them...') + for (const asset of IOS_METADATA_ASSETS) { + const currPath = path.join(DIST_DIR, asset.path) + const md5 = await getMd5(currPath) + const withExtPath = `assets/${md5}.${asset.ext}` + iosAssets.push(withExtPath) + await fsp.cp(currPath, path.join(DEST_DIR, withExtPath)) + } + + console.log('Getting android asset md5s and moving them...') + for (const asset of ANDROID_METADATA_ASSETS) { + const currPath = path.join(DIST_DIR, asset.path) + const md5 = await getMd5(currPath) + const withExtPath = `assets/${md5}.${asset.ext}` + androidAssets.push(withExtPath) + await fsp.cp(currPath, path.join(DEST_DIR, withExtPath)) + } + + const result = { + version: 0, + bundler: 'metro', + fileMetadata: { + ios: { + bundle: iosNewPath, + assets: iosAssets, + }, + android: { + bundle: androidNewPath, + assets: androidAssets, + }, + }, + } + + console.log('Writing metadata...') + await fsp.writeFile( + path.join(DEST_DIR, 'metadata.json'), + JSON.stringify(result), + ) + + console.log('Finished!') + console.log('Metadata:', result) +} + +moveFiles() diff --git a/scripts/bundleUpdate.sh b/scripts/bundleUpdate.sh new file mode 100644 index 00000000..18db81a2 --- /dev/null +++ b/scripts/bundleUpdate.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -o errexit +set -o pipefail +set -o nounset + +rm -rf bundleTempDir +rm -rf bundle.tar.gz + +echo "Creating tarball..." +node scripts/bundleUpdate.js + +cd bundleTempDir || exit + +BUNDLE_VERSION=$(date +%s) +DEPLOYMENT_URL="https://updates.bsky.app/v1/upload?runtime-version=$RUNTIME_VERSION&bundle-version=$BUNDLE_VERSION" + +tar czvf bundle.tar.gz ./* + +echo "Deploying to $DEPLOYMENT_URL..." + +curl -o - --form "bundle=@./bundle.tar.gz" --user "bsky:$DENIS_API_KEY" --basic "$DEPLOYMENT_URL" + +cd .. + +rm -rf bundleTempDir +rm -rf bundle.tar.gz