From e15981985c7f7627ae0c35c1326c670f3b659881 Mon Sep 17 00:00:00 2001 From: Brandon Wilson Date: Wed, 21 Aug 2024 11:36:26 -0500 Subject: [PATCH 1/7] feat(ci): add build provenance attestation --- .github/workflows/deploy-worker.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/.github/workflows/deploy-worker.yml b/.github/workflows/deploy-worker.yml index d1b0617..1482fa5 100644 --- a/.github/workflows/deploy-worker.yml +++ b/.github/workflows/deploy-worker.yml @@ -23,6 +23,8 @@ permissions: jobs: deploy: runs-on: ubuntu-latest + outputs: + WORKER_SCRIPT: ${{ steps.get-script.outputs.WORKER_SCRIPT }} env: wranglerVersion: "3.68.0" @@ -107,6 +109,11 @@ jobs: echo "WORKER_SCRIPT=${worker_script}" >> "$GITHUB_OUTPUT" + - uses: actions/upload-artifact@v4 + with: + name: worker_script + path: ${{ steps.get-script.outputs.WORKER_SCRIPT }} + - name: Deploy Worker uses: cloudflare/wrangler-action@v3 with: @@ -115,3 +122,23 @@ jobs: wranglerVersion: ${{ env.wranglerVersion }} workingDirectory: ${{ github.event.inputs.directory }} command: deploy --no-bundle --name=${{ github.event.inputs.appId }} --dispatch-namespace ${{ github.event.inputs.dispatchNamespace }} ${{ steps.get-script.outputs.WORKER_SCRIPT }} + + attest: + needs: deploy + runs-on: ubuntu-latest + + permissions: + id-token: write + attestations: write + + steps: + - name: Download worker script + uses: actions/download-artifact@v4 + with: + name: worker_script + path: ./ + + - name: Attest Build Provenance + uses: actions/attest-build-provenance@v1 + with: + subject-path: ${{ needs.deploy.outputs.WORKER_SCRIPT }} From 226d0b6ec8996df3ef82afc7116e74af57f94a6d Mon Sep 17 00:00:00 2001 From: Brandon Wilson Date: Thu, 22 Aug 2024 16:00:24 -0500 Subject: [PATCH 2/7] feat(ci): specify worker repo in attestation Add worker branch to workflow input. --- .github/workflows/deploy-worker.yml | 19 +++++++++++++++++-- packages/codius-astro/src/actions/index.ts | 1 + packages/codius-astro/src/lib/github.ts | 3 +++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-worker.yml b/.github/workflows/deploy-worker.yml index 1482fa5..e472047 100644 --- a/.github/workflows/deploy-worker.yml +++ b/.github/workflows/deploy-worker.yml @@ -13,6 +13,9 @@ on: commit: description: "Git commit hash" required: true + branch: + description: "Git branch" + required: true directory: description: "Directory to deploy" required: false @@ -138,7 +141,19 @@ jobs: name: worker_script path: ./ - - name: Attest Build Provenance - uses: actions/attest-build-provenance@v1 + - uses: actions/attest-build-provenance/predicate@d58ddf9f241cd8163408934540d01c3335864d64 # predicate@1.1.2 + id: generate-build-provenance-predicate + + - name: Update Predicate JSON + id: update-predicate + run: | + uri="git+https://github.com/${{ github.event.inputs.repo }}@refs/heads/${{ github.event.inputs.branch }}" + predicate=$(echo '${{ steps.generate-build-provenance-predicate.outputs.predicate }}' | jq -c ".buildDefinition.resolvedDependencies = [{\"uri\": \"$uri\", \"digest\": {\"gitCommit\": \"${{ github.event.inputs.commit }}\"}}]") + echo "predicate=$predicate" >> $GITHUB_OUTPUT + + - uses: actions/attest@2da0b136720d14f01f4dbeeafd1d5a4d76cbe21d # v1.4.0 + id: attest with: subject-path: ${{ needs.deploy.outputs.WORKER_SCRIPT }} + predicate-type: ${{ steps.generate-build-provenance-predicate.outputs.predicate-type }} + predicate: ${{ steps.update-predicate.outputs.predicate }} diff --git a/packages/codius-astro/src/actions/index.ts b/packages/codius-astro/src/actions/index.ts index 4a1247a..1fa2781 100644 --- a/packages/codius-astro/src/actions/index.ts +++ b/packages/codius-astro/src/actions/index.ts @@ -86,6 +86,7 @@ export const server = { owner, repo, commitHash: commit.sha, + branch, directory, dispatchNamespace: context.locals.runtime.env.CF_DISPATCH_NAMESPACE, }) diff --git a/packages/codius-astro/src/lib/github.ts b/packages/codius-astro/src/lib/github.ts index 51c63cd..6d3b73c 100644 --- a/packages/codius-astro/src/lib/github.ts +++ b/packages/codius-astro/src/lib/github.ts @@ -20,6 +20,7 @@ export type WorkflowOptions = { owner: string repo: string commitHash: string + branch: string directory?: string dispatchNamespace: string } @@ -31,6 +32,7 @@ export const triggerWorkflow = async ( owner, repo, commitHash, + branch, directory, dispatchNamespace, }: WorkflowOptions, @@ -48,6 +50,7 @@ export const triggerWorkflow = async ( appId, repo: `${owner}/${repo}`, commit: commitHash, + branch, directory, dispatchNamespace, }, From 8e591bd855ef25f68deef5b34a3cc7f99285cde7 Mon Sep 17 00:00:00 2001 From: Brandon Wilson Date: Thu, 22 Aug 2024 17:03:58 -0500 Subject: [PATCH 3/7] feat(ci): specify worker repo in externalParameters.resolvedDependencies --- .github/workflows/deploy-worker.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-worker.yml b/.github/workflows/deploy-worker.yml index e472047..abc1a2a 100644 --- a/.github/workflows/deploy-worker.yml +++ b/.github/workflows/deploy-worker.yml @@ -148,7 +148,8 @@ jobs: id: update-predicate run: | uri="git+https://github.com/${{ github.event.inputs.repo }}@refs/heads/${{ github.event.inputs.branch }}" - predicate=$(echo '${{ steps.generate-build-provenance-predicate.outputs.predicate }}' | jq -c ".buildDefinition.resolvedDependencies = [{\"uri\": \"$uri\", \"digest\": {\"gitCommit\": \"${{ github.event.inputs.commit }}\"}}]") + resolved_dependencies=$(jq -n --arg uri "$uri" --arg commit "${{ github.event.inputs.commit }}" '[{"uri": $uri, "digest": {"gitCommit": $commit}}]') + predicate=$(echo '${{ steps.generate-build-provenance-predicate.outputs.predicate }}' | jq -c '.buildDefinition.externalParameters.resolvedDependencies = $resolved_dependencies' --argjson resolved_dependencies "$resolved_dependencies") echo "predicate=$predicate" >> $GITHUB_OUTPUT - uses: actions/attest@2da0b136720d14f01f4dbeeafd1d5a4d76cbe21d # v1.4.0 From 5276ac40be1333e73ceaa86c82edafc914542894 Mon Sep 17 00:00:00 2001 From: Brandon Wilson Date: Thu, 22 Aug 2024 17:36:44 -0500 Subject: [PATCH 4/7] feat(ci): include subdirectory in attestation predicate --- .github/workflows/deploy-worker.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/deploy-worker.yml b/.github/workflows/deploy-worker.yml index abc1a2a..5cff960 100644 --- a/.github/workflows/deploy-worker.yml +++ b/.github/workflows/deploy-worker.yml @@ -19,6 +19,7 @@ on: directory: description: "Directory to deploy" required: false + default: "." permissions: contents: read @@ -27,7 +28,7 @@ jobs: deploy: runs-on: ubuntu-latest outputs: - WORKER_SCRIPT: ${{ steps.get-script.outputs.WORKER_SCRIPT }} + WORKER_SCRIPT: ${{ steps.get-script.outputs.WORKER_SCRIPT_FILENAME }} env: wranglerVersion: "3.68.0" @@ -111,11 +112,12 @@ jobs: fi echo "WORKER_SCRIPT=${worker_script}" >> "$GITHUB_OUTPUT" + echo "WORKER_SCRIPT_FILENAME=$(basename $worker_script)" >> "$GITHUB_OUTPUT" - uses: actions/upload-artifact@v4 with: - name: worker_script - path: ${{ steps.get-script.outputs.WORKER_SCRIPT }} + name: ${{ github.event.inputs.appId }} + path: ${{ github.event.inputs.directory }}/${{ steps.get-script.outputs.WORKER_SCRIPT }} - name: Deploy Worker uses: cloudflare/wrangler-action@v3 @@ -138,8 +140,7 @@ jobs: - name: Download worker script uses: actions/download-artifact@v4 with: - name: worker_script - path: ./ + name: ${{ github.event.inputs.appId }} - uses: actions/attest-build-provenance/predicate@d58ddf9f241cd8163408934540d01c3335864d64 # predicate@1.1.2 id: generate-build-provenance-predicate @@ -148,7 +149,7 @@ jobs: id: update-predicate run: | uri="git+https://github.com/${{ github.event.inputs.repo }}@refs/heads/${{ github.event.inputs.branch }}" - resolved_dependencies=$(jq -n --arg uri "$uri" --arg commit "${{ github.event.inputs.commit }}" '[{"uri": $uri, "digest": {"gitCommit": $commit}}]') + resolved_dependencies=$(jq -n --arg uri "$uri" --arg commit "${{ github.event.inputs.commit }}" --arg path "${{ github.event.inputs.directory }}" '[{"uri": $uri, "digest": {"gitCommit": $commit}, "path": $path}]') predicate=$(echo '${{ steps.generate-build-provenance-predicate.outputs.predicate }}' | jq -c '.buildDefinition.externalParameters.resolvedDependencies = $resolved_dependencies' --argjson resolved_dependencies "$resolved_dependencies") echo "predicate=$predicate" >> $GITHUB_OUTPUT From 051287e56b1f91fa8f93d6ef7b520d28f5f1968f Mon Sep 17 00:00:00 2001 From: Brandon Wilson Date: Fri, 23 Aug 2024 11:51:59 -0500 Subject: [PATCH 5/7] chore(ci): make formatting consistent --- .github/workflows/deploy-worker.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/deploy-worker.yml b/.github/workflows/deploy-worker.yml index 5cff960..d766831 100644 --- a/.github/workflows/deploy-worker.yml +++ b/.github/workflows/deploy-worker.yml @@ -28,7 +28,7 @@ jobs: deploy: runs-on: ubuntu-latest outputs: - WORKER_SCRIPT: ${{ steps.get-script.outputs.WORKER_SCRIPT_FILENAME }} + worker-script: ${{ steps.get-script.outputs.worker-script-filename }} env: wranglerVersion: "3.68.0" @@ -50,7 +50,7 @@ jobs: file_path="${directory:+${directory}/}pnpm-lock.yaml" if [ -f "$file_path" ]; then echo "PNPM lock file found" - echo "::set-output name=setup_pnpm::true" + echo "setup_pnpm=true" >> "$GITHUB_OUTPUT" fi - name: Setup Node.js @@ -77,8 +77,8 @@ jobs: id: check-custom-build working-directory: ${{ github.event.inputs.directory }} run: | - CUSTOM_BUILD=$(docker run -i ghcr.io/pelletier/go-toml:v2 tomljson < wrangler.toml | jq -e '.build' > /dev/null && echo "true" || echo "false") - echo "CUSTOM_BUILD=${CUSTOM_BUILD}" >> "$GITHUB_OUTPUT" + custom_build=$(docker run -i ghcr.io/pelletier/go-toml:v2 tomljson < wrangler.toml | jq -e '.build' > /dev/null && echo "true" || echo "false") + echo "custom-build=${custom_build}" >> "$GITHUB_OUTPUT" - name: Bundle/Build Worker uses: cloudflare/wrangler-action@v3 @@ -87,7 +87,7 @@ jobs: workingDirectory: ${{ github.event.inputs.directory }} command: deploy --dry-run ${{ env.OUT_DIR }} --name=${{ github.event.inputs.appId }} --dispatch-namespace ${{ github.event.inputs.dispatchNamespace }} env: - OUT_DIR: ${{ steps.check-custom-build.outputs.CUSTOM_BUILD == 'false' && format('--outdir={0}', env.outDir) || '' }} + OUT_DIR: ${{ steps.check-custom-build.outputs.custom-build == 'false' && format('--outdir={0}', env.outDir) || '' }} - name: Determine worker entry script id: get-script @@ -96,7 +96,7 @@ jobs: wrangler_main=$(docker run -i ghcr.io/pelletier/go-toml:v2 tomljson < wrangler.toml | jq -r '.main') echo "wrangler_main: $wrangler_main" - if [ "${{ steps.check-custom-build.outputs.CUSTOM_BUILD }}" == "false" ]; then + if [ "${{ steps.check-custom-build.outputs.custom-build }}" == "false" ]; then trimmed_wrangler_main=$(echo ${wrangler_main} | sed 's|^\./||') echo "Custom build is false; looking for the bundled script in ${outDir} containing // ${trimmed_wrangler_main}" worker_script=$(grep -rl "// ${trimmed_wrangler_main}" "${{ env.outDir }}" | head -n 1) @@ -107,17 +107,17 @@ jobs: fi if [ -z "$worker_script" ]; then - echo "Error: WORKER_SCRIPT is empty!" + echo "Error: Unable to find worker script!" exit 1 fi - echo "WORKER_SCRIPT=${worker_script}" >> "$GITHUB_OUTPUT" - echo "WORKER_SCRIPT_FILENAME=$(basename $worker_script)" >> "$GITHUB_OUTPUT" + echo "worker-script=${worker_script}" >> "$GITHUB_OUTPUT" + echo "worker-script-filename=$(basename $worker_script)" >> "$GITHUB_OUTPUT" - uses: actions/upload-artifact@v4 with: name: ${{ github.event.inputs.appId }} - path: ${{ github.event.inputs.directory }}/${{ steps.get-script.outputs.WORKER_SCRIPT }} + path: ${{ github.event.inputs.directory }}/${{ steps.get-script.outputs.worker-script }} - name: Deploy Worker uses: cloudflare/wrangler-action@v3 @@ -126,7 +126,7 @@ jobs: accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} wranglerVersion: ${{ env.wranglerVersion }} workingDirectory: ${{ github.event.inputs.directory }} - command: deploy --no-bundle --name=${{ github.event.inputs.appId }} --dispatch-namespace ${{ github.event.inputs.dispatchNamespace }} ${{ steps.get-script.outputs.WORKER_SCRIPT }} + command: deploy --no-bundle --name=${{ github.event.inputs.appId }} --dispatch-namespace ${{ github.event.inputs.dispatchNamespace }} ${{ steps.get-script.outputs.worker-script }} attest: needs: deploy @@ -156,6 +156,6 @@ jobs: - uses: actions/attest@2da0b136720d14f01f4dbeeafd1d5a4d76cbe21d # v1.4.0 id: attest with: - subject-path: ${{ needs.deploy.outputs.WORKER_SCRIPT }} + subject-path: ${{ needs.deploy.outputs.worker-script }} predicate-type: ${{ steps.generate-build-provenance-predicate.outputs.predicate-type }} predicate: ${{ steps.update-predicate.outputs.predicate }} From 2796c12d66c00a10d65a4f979000b5bbcb0171db Mon Sep 17 00:00:00 2001 From: Brandon Wilson Date: Mon, 26 Aug 2024 10:36:25 -0500 Subject: [PATCH 6/7] chore(astro): remove githubWorkflowJobId Report appId in separate workflow job. Add workflow_run.completed webhook handler. Add githubWorkflowRunId index in apps table. --- .github/workflows/deploy-worker.yml | 8 +- packages/codius-astro/README.md | 2 +- .../codius-astro/assets/webhook-event.png | Bin 5555 -> 16224 bytes .../drizzle/0001_fearless_captain_flint.sql | 2 + .../drizzle/meta/0001_snapshot.json | 356 ++++++++++++++++++ .../codius-astro/drizzle/meta/_journal.json | 7 + .../src/components/ViewWorkflowButton.astro | 7 +- packages/codius-astro/src/lib/db/apps.ts | 25 +- packages/codius-astro/src/lib/db/schema.ts | 4 +- .../codius-astro/src/pages/apps/[id].astro | 7 +- .../src/pages/webhooks/github/workflow-job.ts | 29 +- 11 files changed, 397 insertions(+), 50 deletions(-) create mode 100644 packages/codius-astro/drizzle/0001_fearless_captain_flint.sql create mode 100644 packages/codius-astro/drizzle/meta/0001_snapshot.json diff --git a/.github/workflows/deploy-worker.yml b/.github/workflows/deploy-worker.yml index d766831..0457a78 100644 --- a/.github/workflows/deploy-worker.yml +++ b/.github/workflows/deploy-worker.yml @@ -25,6 +25,12 @@ permissions: contents: read jobs: + notify: + runs-on: ubuntu-latest + steps: + - name: ${{github.event.inputs.appId}} + run: echo run identifier ${{ github.run_id }} + deploy: runs-on: ubuntu-latest outputs: @@ -35,8 +41,6 @@ jobs: outDir: "codius-dist" steps: - - name: ${{github.event.inputs.appId}} - run: echo run identifier ${{ github.run_id }} - name: Checkout uses: actions/checkout@v4 with: diff --git a/packages/codius-astro/README.md b/packages/codius-astro/README.md index 4216c82..67b3d5c 100644 --- a/packages/codius-astro/README.md +++ b/packages/codius-astro/README.md @@ -25,7 +25,7 @@ pnpm --filter codius-astro d1 migrations apply --remote > **Note:** Rollback local migrations by deleting the state files with the following command: > > ```bash -> rm .wrangler/state/v3/d1/miniflare-D1DatabaseObject/* +> rm packages/codius-astro/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/* > ``` ### Environment Variables diff --git a/packages/codius-astro/assets/webhook-event.png b/packages/codius-astro/assets/webhook-event.png index 33aab57cfb7de68ea95ee56a06597ec046243192..6eb9df0b5c6231f9b543001dd5dd266d956820d2 100755 GIT binary patch literal 16224 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 LS*A+LB=mm(h!by1 literal 5555 zcmb`LWmFVkv&TWHr9&2w4n<075f;{6=@dbvTfzlli6vY>LXeI{q?@H1sg;gJQW}v) zSh_ne@44UKbM86!!~C9^PxH(?Xa46r6Z%?HiGuVYDIOjkg^IHL8$3LGwmV;ogy@d4 z4n@Lu2fphYB`99mAj|q)Kwt~efZ*X(Mw4Ax5Z=WAXJrFdJUq&d{}?{jslXZ!k6u|t z9-`}Mx}8Shtot?rds}R$$I1nHC@(|Di9gX=g`b9OeZx^{ZX+sh(g76`3I8U{6$msF z2rU$~bd+p^W`6i*CC(%sKuGpLozX2WfDyUKxRauSCIwQSTni$EMpgR9Gzv1S z@=r^C1Df*ic1O=~y<|sl4|KUNF@65ov_`>f`j;!08`EH9nqP-9x;70IdP-)y7R2Ux z!8*1fN!m^o>wCQa^ZMkkot@oFI9#O61cTP`8THNtlpfhLeIqE2C6LeKGGq&xA`WdO%KR(>s=VDnF)osZd$jkW`bUr2jeAJ#ukKudP z1iJk2dv$@2lPs{HSy+tR>r%6^PuF3n+bxX_Q$s?(dh-WW>PoT+~NL0M>2=~u4+xojH_ zZ^i|OqHcWYR8#$kEi9IMt6FtS|5UU#{%@fjttiA~Gq`I1R1* zv^AvVGiC^6FWCG>h(E*K8)7&HX!8^JE-0dMR1;4N#4NL$&1zn5kIT$!BmTW z!#8KURRVy;UYUhZJDl8h)r?t9F@iPJyrG_+nxr;C4Y9~4;i52^5`d^V^z zMfEyBlPX%JbAy<>@TEYq!^=F)-@v*` zivKz1X@w@)XF|ORvs63T_p~enrOs7dOl+E^(~gOey&!e$S%$O)Sf20#oiKa{y-Ff@#GXeNk1YuCcWfjR@lJ}%V_Tp6^p4%Q15~0sox&= znOvw*Lsc@;`UH_vL#WtT|EVecwCU%Ry3b>KDq2-lAxgyqO;R3X`%tuk(s~q;sGsfz zf~CL;A^}L+rRQ{lODB|H-q+LOm0b)+NmXdj9|Y1hgiB^N3b9l&ZE9B)q!dreI3e-= zO3>n0Pg+ej((6~8y^p{0eQHVU-iokBWqCQ21VoBwPKEGtZrw?Oe;i_Ji-!jlBNd_E zwed3D&=Hy!>Gr+gkEbKfTX0A};AdSOcVuII#|eIIqIzouVBOPCtS%4l^4<+ty1H zFV2+*=97zD(jKCM)*oKn+Qc&i`9sSIs9HiDg3YK?B^{IHHll33G8~EnO~5?WlSy-< zf6i#O<_{P|jf&LX(pFz436}iPBD?Ts(ys_Z9GG?C;Z!Saw1G?@{NKhw5vj8kW@JiB z2bTYcm#Cbcc8-iI6f{2wR*6Ol>wk;tBq1)UTQRq9?prX3MzN0)C&|=KZ}TfO6}#Co zwx6lYZt@or8&;k)usnDtLk;{MW^2aP7Dr7<3@ByD5ZDsGds4?oET{${9=wp(?Ay;; zRox?jZseNTu9M3@zK_scm$DL1Jl(ZSCWStUo&P{Va5j9i!Q;ka>R&kIMyd~~H;BD0 zrdM?df9+CC!8$4?BHJ6v{YOQ=MhORK*HF*!0YSme7{X8{HR0P-gMI;I9qEdhz zD1d{2b=Z>tLL$xeUztS@0t{Jdtg8E%Qzs>F#!6E16_Zv9L)eLwk?3;Qh>MATt~cs} z{eHlG>HOOTZ`as%aM7vKKct|M1iLIfbA=~U%T0$FJJD2&k3aTba6h0;-HuR8D3aPe|d zZmThNruD}0PiSO=ku#K?^m#CKiXp?I9Xn~bTCcojJEQpWy=;-;ZwbPbIfKu8eQKLBLeeYsul@2i?HG(IT8k|8xT_L$A{--jS-?WQe{JnCy)Hn%l|I6 z+eKqcB~@l7o3f|#5wJ2CoAZ^i_#0Z~QEutoUvy=zK*hq{0V&9-wBj+@>}Zj=`FFMZ z<~k#8Gb`z5=?xle@9#;6EV^iMo4)_;GgiYnH}d(X<&ae6!{%K;8FJaUPg@5(*ccSq z#h~F%i&J5KyCQQ*{oyLYp=L72ZuSum=JMTlvB=T}DlcS}+kEZh*s=>$9#`-AD*D%) zyUg&2BU0VU7H#xGhuO{4>J!V77v;f^7XzE1$NjD=NLfvJ`Azt`9G0p!5!;~~-9R~R z=JsrEB!at~5vItV*vq^*ta;6-MCuPK@z&}|>l4bTfF6 z%|Kz8rnV-Z1Bca$q7Gd8@Hc`qWx%RJoggauR2hCk2gBjdlMWD5`)ZK}S>B9{3$VL! zTMW%|geA(3D<%P0Jm#C@6Q!k_;4$_&@NsIHM=`4vFa=3M15eDJ9`HJ5jN2G!X{B=j z29G(6I>J6HXgRm6skBVGJDR4-o?Bm~(q*Wij8h7|8a{old}^@~s5L#jBbxF}Qteu* ztw8NKXPL_f*4pNNVc783F6)u|;cV)Y!S1%h?)KipM)T~L_IsK?>X>rS_AN}uK6=m; z%7RqGN?Kzuix3adxCtQLC$&=lC{ zT6>86Hut(;@6Z#)C`MJXZk~UJh^4dhCqnfk(;6p@)7we7;BqVe{Aq-O-|78X9RiJu z5@bhG8RF;D8?k3+AS`1>;7&7-KYUC~_y@6&yWNWit%1@V&RL%#kJ3aR-3_Q<4IUY zr^)%dh77{2gqIjL;cupeF+vX)>~L;}M5{sr4C%`ymjnO8B~IiU1Q)1vHE&54U0$Qdr04G zTGZ)y%7*YZ4pJo&rApfh7R4q=PV3s0{B2;j<&uPwIRK?cr?qp-yOK5hL`FpQ?SF$G z#AoUnnrBw5+dSkg-L4MqF@y_}@m!CM85urd!V6GJ5w%h|Mm)2WwZJA51&kqha+AjP zl9bV`T}?3W#e-qwD-H78oa+gv8mwqIB2Vlm9V6MA${Vw5lMIV$c)Y>(V|Q=TKNmas zZq^+b*7bC+r|}EnI@=-(wGHY*R?l5wz78Yx1OzG4Ihd5EJ~G%T4)kvu^VW?|RA^vU zjRG0qVdG;b4&K2Ui~gTHb*-yi!6$0oGlj;Pw{b#vnyDg5Ci2!F-t20Wz64maFo6%% zkLkhg<1aQaS{6eo)m|XbBCnryV>0`gr^aCrjwq?@@u=#t5g5FneT(84V`SAtl-tt? zfVJ-Z$tx50?Ke=xa2F<&`CFv4=)6DHRO17%S7lWnxKf0qYVImh9lJ7zROmEJNv#sb zLuGz|#niN`2^F}{E*zeV1qY7Ee%*Gg=+7}x))0;cJ-43ND#D8D6_5LsTi`?iuy0C^ zeC62qE-fnxGW3a!v2!8Lbf>V%CdFm!bUk&+Wm@F;MQ?*TI^hCmvBl8yCGTgkpGF&0 zEFi5{dXFC#E*{J3ZT#(_md(8sQluFJ(hejj|K`p5O+M4$%IC~xuvAveg`6g9mFsyx zU!Gbr5Zv>cO6Vf+b9d~X%n-uTDbl{I!Zk_UZ@0p!goSK&8S;eJne}lp%ixDCQ0i~R zhd%qm#Jpj3ZP1lS5l-DE{CWXz|IXzGPEXKyBfgv0G=qzsrLAUr;Syed{pI&` zBgYk>L>-jLjZXM4pL(2NKG`F7)-L1w7{ zHzL`Wvs^d$YZPRW{8uqFZQLZ#-%NPVs1eurDKcTnSfl(Mx5?diGc-6U@t0pNv{Q;Y zj%xF1Uc}tzS+9d&RvI>rMuN3|nwb%*jI?ATu07)bpb?WvSkgRtd%~36X*#+5{Y=aE z&9ypvjC`{dMW@;WX}{}#ytEf|K^?j zmbJyDl{lZCb9T-n?s;v_1zq!2i-5U-4D+j1LiMoTXTpmzIq8?Y;IOk!h*Y}KS61EA zapF-CnJU6@3bP_m-=nA4aDVQGr1E3endV)gEk~B%`n92oW$^PQzXG|*>}mb>6+`Et zRPhMMEJ@ijLA}Sf-+*=SwD4uNS5?R5b|nQ0lWY9l?aZ!ahrZ>SzC^AXjvEfU?x2{2 z++Bl=GPoqmTigNr{OuO}``Ecj{il1h`CW?>IWwjoh{;%^MwEQegUlz4>0`L_oqP-5 z=}WD%?-7_8obCh@XYI_jp-y$g(35o z<|0=2=;nqF=d|u*w=+-$FhvY(ZDMz~mrBF$WTXuJ1nGj%egr}VJf*5kF#;RrPxje< zmC87XCiXF{GAK2Yu|2JRRp)P|OiYpzyjuH7Z26uNR&|aL^sBujBdtg9=i7Ltxl}Io ztXE%B0)CUSu^Q~E3}MTCzDllzYfINljWPk-)U{$~jMwUam-%-5JkJa@_W`NYM%c*Z6AHhML3ZVp3uoTkW0^x9UP!on=!H4CYCQUFxg&rrw(pZNSp5!dFtS8m#mJj{|i1v3?-Xg zo5?SG<$S9g6D#L$f8mvS=L)O&OzSyMZf`F zFV8|*w~y3We(P>pgQv`Zzcnqy=qC3P&e*LPN;rr({R99De%z>F+~F0>Mqj>fJwf$x z-ZZI0EjYM#_et(Q5G_WB>YUps5JU^_nQQRQdmcTV-WUj#=XgNCx%RdDKVtE}lJWn_ d82lS{^_$=(DWz(SyG1LWih`zm8Pq)Be*g_Ut2h7v diff --git a/packages/codius-astro/drizzle/0001_fearless_captain_flint.sql b/packages/codius-astro/drizzle/0001_fearless_captain_flint.sql new file mode 100644 index 0000000..80a8010 --- /dev/null +++ b/packages/codius-astro/drizzle/0001_fearless_captain_flint.sql @@ -0,0 +1,2 @@ +CREATE INDEX `idx_apps_github_workflow_run_id` ON `apps` (`github_workflow_run_id`);--> statement-breakpoint +ALTER TABLE `apps` DROP COLUMN `github_workflow_job_id`; \ No newline at end of file diff --git a/packages/codius-astro/drizzle/meta/0001_snapshot.json b/packages/codius-astro/drizzle/meta/0001_snapshot.json new file mode 100644 index 0000000..9e1a568 --- /dev/null +++ b/packages/codius-astro/drizzle/meta/0001_snapshot.json @@ -0,0 +1,356 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "57fb6080-4ec4-4c8b-bc82-712ed5c88cc6", + "prevId": "ca561cda-e276-4c9a-879e-c97d1d02d7d6", + "tables": { + "apps": { + "name": "apps", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "github_owner": { + "name": "github_owner", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "repo": { + "name": "repo", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "commit_hash": { + "name": "commit_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "directory": { + "name": "directory", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "github_workflow_run_id": { + "name": "github_workflow_run_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + }, + "deleted_at": { + "name": "deleted_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "idx_apps_user_id": { + "name": "idx_apps_user_id", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "idx_apps_github_workflow_run_id": { + "name": "idx_apps_github_workflow_run_id", + "columns": [ + "github_workflow_run_id" + ], + "isUnique": false + }, + "apps_user_id_github_owner_repo_commit_hash_directory_deleted_at_unique": { + "name": "apps_user_id_github_owner_repo_commit_hash_directory_deleted_at_unique", + "columns": [ + "user_id", + "github_owner", + "repo", + "commit_hash", + "directory", + "deleted_at" + ], + "isUnique": true + } + }, + "foreignKeys": { + "apps_user_id_users_id_fk": { + "name": "apps_user_id_users_id_fk", + "tableFrom": "apps", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "payments": { + "name": "payments", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "amount": { + "name": "amount", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "stripe_checkout_session_id": { + "name": "stripe_checkout_session_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "app_id": { + "name": "app_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + } + }, + "indexes": {}, + "foreignKeys": { + "payments_app_id_apps_id_fk": { + "name": "payments_app_id_apps_id_fk", + "tableFrom": "payments", + "tableTo": "apps", + "columnsFrom": [ + "app_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "payments_user_id_users_id_fk": { + "name": "payments_user_id_users_id_fk", + "tableFrom": "payments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "sessions": { + "name": "sessions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + } + }, + "indexes": {}, + "foreignKeys": { + "sessions_user_id_users_id_fk": { + "name": "sessions_user_id_users_id_fk", + "tableFrom": "sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "github_id": { + "name": "github_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + } + }, + "indexes": { + "users_github_id_unique": { + "name": "users_github_id_unique", + "columns": [ + "github_id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/packages/codius-astro/drizzle/meta/_journal.json b/packages/codius-astro/drizzle/meta/_journal.json index eca5637..38c822d 100644 --- a/packages/codius-astro/drizzle/meta/_journal.json +++ b/packages/codius-astro/drizzle/meta/_journal.json @@ -8,6 +8,13 @@ "when": 1722449250619, "tag": "0000_tidy_nekra", "breakpoints": true + }, + { + "idx": 1, + "version": "6", + "when": 1724711940074, + "tag": "0001_fearless_captain_flint", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/codius-astro/src/components/ViewWorkflowButton.astro b/packages/codius-astro/src/components/ViewWorkflowButton.astro index 0442ff4..20c0182 100644 --- a/packages/codius-astro/src/components/ViewWorkflowButton.astro +++ b/packages/codius-astro/src/components/ViewWorkflowButton.astro @@ -5,13 +5,12 @@ import { scope } from "simple:scope" type Props = { workflowRunId: number - workflowJobId: number } -const { workflowRunId, workflowJobId } = Astro.props +const { workflowRunId } = Astro.props --- - +