[READ-ONLY] Mirror of https://github.com/danielroe/roe.dev. This is the code and content for my personal website, built in Nuxt. roe.dev
0

Configure Feed

Select the types of activity you want to include in your feed.

chore: remove some workarounds (#1670)

author
Daniel Roe
committer
GitHub
date (Jul 14, 2025, 10:54 AM +0200) commit 8ac05a0c parent 089a3c66
+5 -257
-214
.github/workflows/cf-sync.yml
··· 1 - name: Cloudflare Deployment Sync 2 - 3 - on: 4 - issue_comment: 5 - types: [created, edited] 6 - 7 - jobs: 8 - process-cloudflare-comment: 9 - # Only process comments from the Cloudflare bot on PRs 10 - if: github.event.issue.pull_request && github.event.comment.user.login == 'cloudflare-workers-and-pages[bot]' 11 - runs-on: ubuntu-latest 12 - # Add workflow permissions to create deployments 13 - permissions: 14 - pull-requests: read 15 - contents: write 16 - deployments: write 17 - 18 - steps: 19 - - name: Get PR branch 20 - id: get-pr 21 - uses: actions/github-script@v7 22 - with: 23 - script: | 24 - const { owner, repo, number } = context.issue; 25 - const pr = await github.rest.pulls.get({ 26 - owner, 27 - repo, 28 - pull_number: number 29 - }); 30 - return { 31 - branch: pr.data.head.ref, 32 - sha: pr.data.head.sha 33 - }; 34 - 35 - - name: Parse comment for deployment status 36 - id: parse-comment 37 - uses: actions/github-script@v7 38 - with: 39 - script: | 40 - const commentBody = context.payload.comment.body; 41 - 42 - const isDeployStarting = commentBody.includes('In progress'); 43 - const isDeployFinished = commentBody.includes('Deployment successful!'); 44 - const isDeployFailed = commentBody.includes('❌') || commentBody.includes('Build failed') || commentBody.includes('Deployment failed'); 45 - 46 - let status = ''; 47 - let deployUrl = ''; 48 - 49 - if (isDeployStarting) { 50 - status = 'starting'; 51 - } else if (isDeployFinished) { 52 - status = 'finished'; 53 - // Extract URL from the new Cloudflare Workers format: <a href='https://...'>Commit Preview URL</a> 54 - const urlMatch = commentBody.match(/<a href='([^']+)'>Commit Preview URL<\/a>/); 55 - if (urlMatch) { 56 - deployUrl = urlMatch[1]; 57 - } 58 - } else if (isDeployFailed) { 59 - status = 'failed'; 60 - } else { 61 - status = 'unknown'; 62 - } 63 - 64 - console.log(`Detected deployment status: ${status}`); 65 - console.log(`Deploy URL: ${deployUrl}`); 66 - // Set outputs directly 67 - core.setOutput('status', status); 68 - core.setOutput('deployUrl', deployUrl || ''); 69 - 70 - - name: Create deployment 71 - id: deployment 72 - # Use outputs directly, not nested in result 73 - if: steps.parse-comment.outputs.status == 'starting' || steps.parse-comment.outputs.status == 'finished' || steps.parse-comment.outputs.status == 'failed' 74 - uses: actions/github-script@v7 75 - with: 76 - github-token: ${{ secrets.WORKFLOW_PAT || secrets.GITHUB_TOKEN }} 77 - script: | 78 - const { owner, repo } = context.repo; 79 - const prNumber = context.issue.number; 80 - 81 - // Parse the JSON result string from get-pr step 82 - const prData = JSON.parse('${{ steps.get-pr.outputs.result }}'); 83 - const sha = prData.sha; 84 - const branch = prData.branch; 85 - 86 - const status = '${{ steps.parse-comment.outputs.status }}'; 87 - 88 - console.log(`Processing deployment for PR #${prNumber}, branch ${branch}, SHA ${sha}, status: ${status}`); 89 - 90 - // Get existing deployments for this environment and PR 91 - const existingDeployments = await github.rest.repos.listDeployments({ 92 - owner, 93 - repo, 94 - environment: 'cloudflare-preview', 95 - ref: sha 96 - }); 97 - 98 - let deploymentId; 99 - let existingInProgressDeployment = false; 100 - 101 - // Check if we already have a deployment in progress 102 - if (existingDeployments.data.length > 0) { 103 - // For each existing deployment, check if it's in progress 104 - for (const deployment of existingDeployments.data) { 105 - // Ensure deployment is defined before accessing its id 106 - if (!deployment) continue; 107 - 108 - const statuses = await github.rest.repos.listDeploymentStatuses({ 109 - owner, 110 - repo, 111 - deployment_id: deployment.id 112 - }); 113 - 114 - const latestStatus = statuses.data[0]; 115 - if (latestStatus && latestStatus.state === 'in_progress') { 116 - existingInProgressDeployment = true; 117 - deploymentId = deployment.id; 118 - console.log(`Found existing in-progress deployment with ID: ${deploymentId}`); 119 - break; 120 - } 121 - } 122 - } 123 - 124 - // If there's no existing deployment or no in-progress deployment and we're starting a new one 125 - if ((existingDeployments.data.length === 0 || !existingInProgressDeployment) && status === 'starting') { 126 - console.log(`Creating new deployment for PR #${prNumber}, branch ${branch}, SHA ${sha}`); 127 - 128 - const deployment = await github.rest.repos.createDeployment({ 129 - owner, 130 - repo, 131 - ref: sha, 132 - description: `Cloudflare Workers deployment for PR #${prNumber}`, 133 - environment: 'cloudflare-preview', 134 - auto_merge: false, 135 - required_contexts: [] 136 - }); 137 - 138 - // Ensure deployment.data exists before accessing id 139 - if (deployment && deployment.data) { 140 - deploymentId = deployment.data.id; 141 - console.log(`Created new deployment with ID: ${deploymentId}`); 142 - 143 - // Set status to in_progress 144 - await github.rest.repos.createDeploymentStatus({ 145 - owner, 146 - repo, 147 - deployment_id: deploymentId, 148 - state: 'in_progress', 149 - description: 'Cloudflare Workers is deploying' 150 - }); 151 - } else { 152 - console.log('Failed to create deployment: deployment or deployment.data is undefined'); 153 - } 154 - } else if (!deploymentId && existingDeployments.data.length > 0 && existingDeployments.data[0]) { 155 - // If we didn't find an in-progress deployment but we have existing ones 156 - deploymentId = existingDeployments.data[0].id; 157 - console.log(`Using most recent deployment ID: ${deploymentId}`); 158 - } 159 - 160 - // Only set deployment ID as output if it's defined 161 - if (deploymentId) { 162 - core.setOutput('deploymentId', deploymentId.toString()); 163 - } else { 164 - console.log('No valid deployment ID found'); 165 - core.setOutput('deploymentId', ''); 166 - } 167 - 168 - - name: Update deployment status (finished) 169 - if: steps.parse-comment.outputs.status == 'finished' 170 - uses: actions/github-script@v7 171 - with: 172 - github-token: ${{ secrets.WORKFLOW_PAT || secrets.GITHUB_TOKEN }} 173 - script: | 174 - const { owner, repo } = context.repo; 175 - const prNumber = context.issue.number; 176 - const deployUrl = '${{ steps.parse-comment.outputs.deployUrl }}'; 177 - const deploymentId = parseInt('${{ steps.deployment.outputs.deploymentId }}'); 178 - 179 - console.log(`Updating deployment ${deploymentId} for PR #${prNumber} with URL ${deployUrl}`); 180 - 181 - await github.rest.repos.createDeploymentStatus({ 182 - owner, 183 - repo, 184 - deployment_id: deploymentId, 185 - state: 'success', 186 - environment_url: deployUrl, 187 - log_url: deployUrl, 188 - description: 'Cloudflare Workers deployment successful' 189 - }); 190 - 191 - console.log(`Updated deployment ${deploymentId} status to success with URL ${deployUrl}`); 192 - 193 - - name: Update deployment status (failed) 194 - if: steps.parse-comment.outputs.status == 'failed' 195 - uses: actions/github-script@v7 196 - with: 197 - github-token: ${{ secrets.WORKFLOW_PAT || secrets.GITHUB_TOKEN }} 198 - script: | 199 - const { owner, repo } = context.repo; 200 - const prNumber = context.issue.number; 201 - const deploymentId = parseInt('${{ steps.deployment.outputs.deploymentId }}'); 202 - 203 - console.log(`Updating deployment ${deploymentId} for PR #${prNumber} as failed`); 204 - 205 - // Mark the deployment as failed 206 - await github.rest.repos.createDeploymentStatus({ 207 - owner, 208 - repo, 209 - deployment_id: deploymentId, 210 - state: 'failure', 211 - description: 'Cloudflare Workers deployment failed' 212 - }); 213 - 214 - console.log(`Updated deployment ${deploymentId} status to failure`);
+2 -2
app/app.vue
··· 13 13 </template> 14 14 15 15 <script lang="ts" setup> 16 - import { joinURL, withTrailingSlash } from 'ufo' 16 + import { joinURL, withoutTrailingSlash } from 'ufo' 17 17 18 18 const route = useRoute() 19 19 ··· 52 52 ) 53 53 54 54 const { path = '/' } = route.fullPath.match(PATH_RE)?.groups ?? {} 55 - const url = withTrailingSlash(`https://roe.dev${path}`) 55 + const url = withoutTrailingSlash(`https://roe.dev${path}`) 56 56 57 57 useServerHead({ 58 58 meta: () => [
+1 -1
content/blog/diversity.md
··· 72 72 73 73 I'm an outsider to the tech world, even if I'm privileged in many other ways. I know what it was to be welcomed in. I'd like that to be true for many more people too. 'Freely you have received, freely give,' are words that mean a lot to me. Plus, half of the fun of open source is in working collaboratively. 74 74 75 - So from my point of view, open source is and should be _open_. Come on in! We'd love to have you. And [have a chat with me](/blog/open-invitation/) if that would be helpful! 75 + So from my point of view, open source is and should be _open_. Come on in! We'd love to have you. And [have a chat with me](/blog/open-invitation) if that would be helpful! 76 76 77 77 ## Why write this? 78 78
-14
modules/cloudflare-vars.ts
··· 1 - import { useRuntimeConfig, defineNuxtModule, useNuxt } from 'nuxt/kit' 2 - 3 - export default defineNuxtModule({ 4 - meta: { 5 - name: 'cloudflare-vars', 6 - }, 7 - setup () { 8 - const nuxt = useNuxt() 9 - 10 - nuxt.hook('nitro:config', config => { 11 - config.runtimeConfig = useRuntimeConfig() 12 - }) 13 - }, 14 - })
+1 -18
nuxt.config.ts
··· 178 178 sourcemap: { client: true, server: false }, 179 179 180 180 experimental: { 181 - buildCache: false, 182 - defaults: { 183 - nuxtLink: { 184 - trailingSlash: 'append', 185 - }, 186 - }, 187 181 viewTransition: true, 188 182 }, 189 183 190 184 compatibilityDate: '2025-06-09', 191 185 192 186 nitro: { 193 - cloudflare: { 194 - deployConfig: true, 195 - wrangler: { 196 - name: 'roe', 197 - observability: { 198 - logs: { 199 - enabled: true, 200 - }, 201 - }, 202 - }, 203 - }, 204 187 experimental: { 205 188 tasks: true, 206 189 }, ··· 217 200 future: { nativeSWR: true }, 218 201 prerender: { 219 202 crawlLinks: true, 220 - routes: ['/', '/live', '/rss.xml', '/voted/', '/work/', '/feedback/', '/ama/', '/ai/'], 203 + routes: ['/', '/live', '/rss.xml', '/voted', '/work', '/feedback', '/ama', '/ai'], 221 204 ignore: ['/__nuxt_content'], 222 205 }, 223 206 hooks: {
-7
server/api/logger.get.ts
··· 1 - export default defineEventHandler(async event => { 2 - // try to work around missing env variables on cloudflare workers 3 - console.log('runtime config 1', useRuntimeConfig(event)) 4 - console.log('runtime config 2', useRuntimeConfig()) 5 - console.log('runtime config 3', useRuntimeConfig(event)) 6 - console.log('env', event.context) 7 - })
+1 -1
test/unit/bundle.spec.ts
··· 79 79 stats.server = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir) 80 80 expect 81 81 .soft(roundToKilobytes(stats.server.totalBytes)) 82 - .toMatchInlineSnapshot(`"816k"`) 82 + .toMatchInlineSnapshot(`"815k"`) 83 83 84 84 const modules = await analyzeSizes('node_modules/**/*', serverDir) 85 85 expect