Skip to content

[Don't merge] Added staging tests to CI/CD #687

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

rmgpinto
Copy link
Collaborator

closes https://linear.app/ghost/issue/PROD-1779

  • Added a CI/CD step that runs tests in staging. This will attempt to catch errors in GCP components before being shipped to production.

Copy link

coderabbitai bot commented May 19, 2025

Walkthrough

The .github/workflows/cicd.yml file was updated to comment out the "Run Tests" step in the build-test-push job and add new "Deploy Tests to Cloud Run" steps in both the deploy-pr and deploy-staging jobs. In deploy-pr, a Cloud Run job named stg-pr-<PR number>-tests is deployed using the ActivityPub image tagged with the migrations Docker version, running yarn _test:single immediately and waiting for completion, conditioned on the ephemeral staging label. It is followed by a step to destroy test databases matching the PR number pattern. In deploy-staging, a similar Cloud Run job named stg-<region_name>-activitypub-tests is deployed only for the europe-west4 region, with a subsequent database cleanup step. Both deployment steps skip default labels and add a commit SHA label.

The Dockerfile was modified to copy the vitest.config.ts file into the container before setting the environment to production and running the build, with no other changes.

The src/test/db.ts file’s createTestDb function was updated to support MySQL connections via a Unix socket path if MYSQL_SOCKET_PATH is set, adjusting connection configurations accordingly. The test database name is conditionally prefixed with a sanitized MYSQL_DATABASE if it contains 'pr-'. Table cloning logic changed from CREATE TABLE ... LIKE to using the original table's SHOW CREATE TABLE statement, removing CONSTRAINT lines and cleaning trailing commas before executing the adjusted SQL. The function signature remains unchanged.

A new integration test suite was added in src/storage/gcloud-storage/gcp-storage.service.integration.test.ts to test the GCPStorageService methods saveFile and verifyImageUrl. The suite covers saving JPEG images, rejecting oversized or unsupported files, and verifying image URLs with various valid and invalid cases, adapting assertions based on the GCP emulator environment.

Possibly related PRs

Suggested labels

ricardo-staging-1.ghost.is

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 04c49e6 and 402f931.

📒 Files selected for processing (1)
  • .github/workflows/cicd.yml (2 hunks)
🧰 Additional context used
🪛 actionlint (1.7.7)
.github/workflows/cicd.yml

244-244: property "region" is not defined in object type {}

(expression)


248-248: property "region" is not defined in object type {}

(expression)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Build, Test and Push
  • GitHub Check: Build, Test and Push

Comment on lines 243 to 254
- name: "Deploy Tests to Cloud Run"
if: ${{ matrix.region == 'europe-west4' }}
uses: google-github-actions/deploy-cloudrun@v2
with:
image: europe-docker.pkg.dev/ghost-activitypub/activitypub/activitypub:${{ needs.build-test-push.outputs.migrations_docker_version }}
region: ${{ matrix.region }}
job: stg-pr-${{ github.event.pull_request.number }}-tests
flags: --command="yarn _test:single" --wait --execute-now
skip_default_labels: true
labels: |-
commit-sha=${{ github.sha }}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Critical: matrix.region undefined in deploy-pr job, test step never runs & wrong image tag

In the deploy-pr job, there is no strategy.matrix.region, so:

if: ${{ matrix.region == 'europe-west4' }}

always evaluates to false and the "Deploy Tests to Cloud Run" step will never execute. Additionally, the image is incorrectly using the migrations_docker_version output instead of activitypub_docker_version, so even if it ran it would deploy the wrong container.

Apply this diff:

@@ -243,7 +243,7 @@
       - name: "Deploy Tests to Cloud Run"
-        if: ${{ matrix.region == 'europe-west4' }}
+        # Only run tests when ephemeral staging is enabled
+        if: ${{ steps.check-labels.outputs.is_ephemeral_staging == 'true' }}
         uses: google-github-actions/deploy-cloudrun@v2
         with:
-          image: europe-docker.pkg.dev/ghost-activitypub/activitypub/activitypub:${{ needs.build-test-push.outputs.migrations_docker_version }}
+          image: europe-docker.pkg.dev/ghost-activitypub/activitypub/activitypub:${{ needs.build-test-push.outputs.activitypub_docker_version }}
           region: europe-west4
           job: stg-pr-${{ github.event.pull_request.number }}-tests
           flags: --command="yarn _test:single" --wait --execute-now

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 actionlint (1.7.7)

244-244: property "region" is not defined in object type {}

(expression)


248-248: property "region" is not defined in object type {}

(expression)

🤖 Prompt for AI Agents
In .github/workflows/cicd.yml around lines 243 to 254, the "Deploy Tests to
Cloud Run" step uses an undefined matrix.region in its if condition, causing it
to never run, and it references the wrong image tag output. Fix this by removing
or correcting the if condition to ensure the step runs as intended, and update
the image tag to use the correct output variable activitypub_docker_version
instead of migrations_docker_version.

@rmgpinto rmgpinto force-pushed the add-staging-cicd-tests branch from 402f931 to b1dfabf Compare May 19, 2025 10:00
@rmgpinto rmgpinto force-pushed the add-staging-cicd-tests branch from b1dfabf to 3ce9e17 Compare May 19, 2025 10:28
@rmgpinto rmgpinto force-pushed the add-staging-cicd-tests branch from 3ce9e17 to 70bba90 Compare May 19, 2025 10:43
@rmgpinto rmgpinto force-pushed the add-staging-cicd-tests branch from 70bba90 to d9c3583 Compare May 19, 2025 11:12
@rmgpinto rmgpinto force-pushed the add-staging-cicd-tests branch from d9c3583 to 33a933f Compare May 19, 2025 11:17
@rmgpinto rmgpinto force-pushed the add-staging-cicd-tests branch from 33a933f to d20d4f6 Compare May 19, 2025 13:57
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
src/test/db.ts (1)

69-79: 🛠️ Refactor suggestion

Update cleanup connection to use socket path if available

The cleanup connection in the afterAll hook doesn't use the socket path connection option that was added to the other connections. For consistency, consider updating it to use the same connection logic.

afterAll(async () => {
    await dbClient.destroy();
    const systemClient = knex({
        client: 'mysql2',
-       connection: {
-           host: process.env.MYSQL_HOST,
-           port: Number.parseInt(process.env.MYSQL_PORT!),
-           user: process.env.MYSQL_USER,
-           password: process.env.MYSQL_PASSWORD,
-           database: 'mysql',
-           timezone: '+00:00',
-       },
+       connection: process.env.MYSQL_SOCKET_PATH
+           ? {
+                 socketPath: process.env.MYSQL_SOCKET_PATH,
+                 user: process.env.MYSQL_USER,
+                 password: process.env.MYSQL_PASSWORD,
+                 database: 'mysql',
+                 timezone: '+00:00',
+             }
+           : {
+                 host: process.env.MYSQL_HOST,
+                 port: Number.parseInt(process.env.MYSQL_PORT!),
+                 user: process.env.MYSQL_USER,
+                 password: process.env.MYSQL_PASSWORD,
+                 database: 'mysql',
+                 timezone: '+00:00',
+             },
    });
    await systemClient.raw(`DROP DATABASE ${dbName}`);
    await systemClient.destroy();
});

If you implement the getDbConnectionConfig function suggested earlier, you could also reuse it here with a parameter to override the database name:

const systemClient = knex({
    client: 'mysql2',
    connection: {
        ...getDbConnectionConfig(),
        database: 'mysql'
    },
});
🧹 Nitpick comments (1)
src/test/db.ts (1)

12-27: Enhance connection configuration by applying DRY principles

The connection configuration is duplicated for both the systemClient and dbClient objects (lines 12-27 and 49-64). Consider extracting this logic into a reusable function to improve maintainability.

You could create a function that returns the appropriate connection configuration:

function getDbConnectionConfig() {
    return process.env.MYSQL_SOCKET_PATH
        ? {
              socketPath: process.env.MYSQL_SOCKET_PATH,
              user: process.env.MYSQL_USER,
              password: process.env.MYSQL_PASSWORD,
              database: process.env.MYSQL_DATABASE,
              timezone: '+00:00',
          }
        : {
              host: process.env.MYSQL_HOST,
              port: Number.parseInt(process.env.MYSQL_PORT!),
              user: process.env.MYSQL_USER,
              password: process.env.MYSQL_PASSWORD,
              database: process.env.MYSQL_DATABASE,
              timezone: '+00:00',
          };
}

Then use it in both places:

const systemClient = knex({
    client: 'mysql2',
    connection: getDbConnectionConfig(),
});

// And later
const dbClient = knex({
    client: 'mysql2',
    connection: getDbConnectionConfig(),
});
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 33a933f and d20d4f6.

📒 Files selected for processing (3)
  • .github/workflows/cicd.yml (3 hunks)
  • Dockerfile (1 hunks)
  • src/test/db.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • Dockerfile
  • .github/workflows/cicd.yml
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: (ephemeral staging) Deploy

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🔭 Outside diff range comments (1)
src/test/db.ts (1)

74-89: 🛠️ Refactor suggestion

Inconsistent connection method in afterAll cleanup.

The afterAll hook doesn't support socket path connections like the rest of the code. It always uses TCP connections (host/port) for cleanup, which could cause issues in environments configured to use socket connections.

For consistency, update the afterAll cleanup to use the same connection logic:

afterAll(async () => {
    await dbClient.destroy();
    const systemClient = knex({
        client: 'mysql2',
-        connection: {
-            host: process.env.MYSQL_HOST,
-            port: Number.parseInt(process.env.MYSQL_PORT!),
-            user: process.env.MYSQL_USER,
-            password: process.env.MYSQL_PASSWORD,
-            database: 'mysql',
-            timezone: '+00:00',
-        },
+        connection: process.env.MYSQL_SOCKET_PATH
+            ? {
+                  socketPath: process.env.MYSQL_SOCKET_PATH,
+                  user: process.env.MYSQL_USER,
+                  password: process.env.MYSQL_PASSWORD,
+                  database: 'mysql',
+                  timezone: '+00:00',
+              }
+            : {
+                  host: process.env.MYSQL_HOST,
+                  port: Number.parseInt(process.env.MYSQL_PORT!),
+                  user: process.env.MYSQL_USER,
+                  password: process.env.MYSQL_PASSWORD,
+                  database: 'mysql',
+                  timezone: '+00:00',
+              },
    });
    await systemClient.raw(`DROP DATABASE ${dbName}`);
    await systemClient.destroy();
});
🧹 Nitpick comments (2)
src/test/db.ts (2)

40-49: Improved table cloning strategy, but consider foreign key handling.

The new approach of using SHOW CREATE TABLE and filtering out constraints is more sophisticated than the previous method. However, it might still have issues with foreign keys or other complex relationships.

Consider adding specific handling for foreign keys if your schema uses them:

const createTableSql = createTableResult[0]['Create Table']
    .replace('CREATE TABLE ', `CREATE TABLE \`${dbName}\`.`)
    .split('\n')
-    .filter((line: string) => !line.trim().startsWith('CONSTRAINT'))
+    .filter((line: string) => {
+        // Filter out constraints but keep track of foreign keys for later if needed
+        const isConstraint = line.trim().startsWith('CONSTRAINT');
+        return !isConstraint;
+    })
    .join('\n')
    .replace(/,\n\)/, '\n)'); // clean up trailing comma

9-92: Consider adding error handling for database operations.

The function lacks comprehensive error handling. If database operations fail, errors might not be properly caught, and resources might not be cleaned up correctly.

Consider wrapping the database operations in try-catch blocks and ensuring proper cleanup:

export async function createTestDb() {
+    let systemClient;
+    let dbClient;
+    let dbName;
+    
+    try {
        const systemClient = knex({
            // ... existing configuration
        });

        const dbName = `${process.env.MYSQL_DATABASE?.includes('pr-') ? ... }`;

        await systemClient.raw(`CREATE DATABASE ${dbName}`);
        
        // ... clone tables logic
        
        await systemClient.destroy();
        
        const dbClient = knex({
            // ... existing configuration
        });
        
        // Setup cleanup in afterAll
        afterAll(async () => {
+            try {
                await dbClient?.destroy();
                const cleanupClient = knex({
                    // ... configuration with socket path support
                });
                await cleanupClient.raw(`DROP DATABASE ${dbName}`);
                await cleanupClient.destroy();
+            } catch (error) {
+                console.error('Error during test database cleanup:', error);
+            }
        });
        
        return dbClient;
+    } catch (error) {
+        // Clean up resources if initialization fails
+        await systemClient?.destroy();
+        await dbClient?.destroy();
+        
+        // Try to drop the database if it was created
+        if (dbName) {
+            try {
+                const cleanupClient = knex({
+                    // ... configuration with socket path support
+                });
+                await cleanupClient.raw(`DROP DATABASE IF EXISTS ${dbName}`);
+                await cleanupClient.destroy();
+            } catch (cleanupError) {
+                console.error('Error during cleanup after initialization failure:', cleanupError);
+            }
+        }
+        
+        throw error; // Re-throw the original error
+    }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a065b74 and e4dff58.

📒 Files selected for processing (3)
  • .github/workflows/cicd.yml (3 hunks)
  • Dockerfile (1 hunks)
  • src/test/db.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • Dockerfile
  • .github/workflows/cicd.yml
🔇 Additional comments (3)
src/test/db.ts (3)

12-27: Support for both socket and TCP connections is a good enhancement.

The addition of conditional connection logic based on the presence of MYSQL_SOCKET_PATH improves flexibility and allows the tests to run in different environments, such as Cloud Run where socket connections might be preferred.


30-30: Smart database naming strategy for PR environments.

The enhanced naming logic makes it easier to identify test databases in PR environments by including a sanitized version of the PR database name as a prefix when applicable. This is helpful for debugging and monitoring in CI/CD pipelines.


56-71: Correctly using the test database name in connection configuration.

This change properly connects to the temporary test database using the dbName variable instead of process.env.MYSQL_DATABASE, which resolves the issue mentioned in the past review comment.

@rmgpinto rmgpinto changed the title Added staging tests to CI/CD [Don't merge] Added staging tests to CI/CD May 21, 2025
@rmgpinto rmgpinto force-pushed the add-staging-cicd-tests branch from e4dff58 to a4cf6e8 Compare May 21, 2025 10:49
@rmgpinto rmgpinto force-pushed the add-staging-cicd-tests branch from a4cf6e8 to 28cacc3 Compare May 21, 2025 11:16
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (2)
.github/workflows/cicd.yml (2)

243-254: ⚠️ Potential issue

Critical: Test jobs running the wrong container image

The Deploy Tests to Cloud Run step in the deploy-pr job still references the migrations image tag (migrations_docker_version) instead of the ActivityPub service image. This will run tests against the wrong container.
Apply this change:

-          image: europe-docker.pkg.dev/ghost-activitypub/activitypub/activitypub:${{ needs.build-test-push.outputs.migrations_docker_version }}
+          image: europe-docker.pkg.dev/ghost-activitypub/activitypub/activitypub:${{ needs.build-test-push.outputs.activitypub_docker_version }}

329-340: ⚠️ Potential issue

Critical: Test jobs running the wrong container image

The Deploy Tests to Cloud Run step in the deploy-staging job still uses the migrations image tag (migrations_docker_version). It should use the ActivityPub service image:

-          image: europe-docker.pkg.dev/ghost-activitypub/activitypub/activitypub:${{ needs.build-test-push.outputs.migrations_docker_version }}
+          image: europe-docker.pkg.dev/ghost-activitypub/activitypub/activitypub:${{ needs.build-test-push.outputs.activitypub_docker_version }}
🧹 Nitpick comments (1)
.github/workflows/cicd.yml (1)

105-107: Remove obsolete commented test step

The inline Run Tests step has been commented out. If it’s no longer needed, consider removing these commented lines to keep the workflow clean.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a4cf6e8 and 28cacc3.

📒 Files selected for processing (3)
  • .github/workflows/cicd.yml (3 hunks)
  • Dockerfile (1 hunks)
  • src/test/db.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • Dockerfile
  • src/test/db.ts

closes https://linear.app/ghost/issue/PROD-1779

- Added a CI/CD step that runs tests in staging. This will attempt to
catch errors in GCP components before being shipped to production.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/storage/gcloud-storage/gcp-storage.service.integration.test.ts (3)

1-16: Well-structured imports and setup for the integration test.

The imports, logger mock, and test constants are well organized. However, I notice the test might be assuming the GCP_BUCKET_NAME environment variable is set (used later on line 141).

Consider adding validation for required environment variables at the beginning of the test to provide clearer error messages if they're missing.


25-54: Good validation logic for successful file upload.

The test appropriately checks both the emulator and production scenarios, with different verification strategies for each environment.

Consider adding a teardown step to clean up the files uploaded during tests to prevent accumulation of test data in your storage bucket.


92-113: Comprehensive URL verification test.

The test correctly saves a file first and then verifies its URL. The validation logic is thorough.

To make the test more robust against potential race conditions when running against real GCP services, consider adding a small delay between saving the file and verifying it, as cloud storage systems can sometimes have propagation delays.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b5e5231 and 8e07c4d.

⛔ Files ignored due to path filters (1)
  • src/storage/gcloud-storage/assets/dog.jpg is excluded by !**/*.jpg
📒 Files selected for processing (1)
  • src/storage/gcloud-storage/gcp-storage.service.integration.test.ts (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Build, Test and Push
🔇 Additional comments (6)
src/storage/gcloud-storage/gcp-storage.service.integration.test.ts (6)

17-23: LGTM - Good test initialization practice.

The service is properly initialized in a beforeAll block, which is good practice to avoid repetitive setup code.


56-72: LGTM - Proper size limit testing.

Good test for the file size limit, creating a buffer larger than the allowed size and verifying the correct error is returned.


74-90: LGTM - Good file type validation test.

The test properly verifies that unsupported file types are rejected with the correct error code.


115-123: LGTM - Good invalid URL test.

The test properly checks that invalid URLs are rejected with the correct error code.


125-137: Good environment-aware testing for invalid paths.

The test correctly handles different error codes based on whether the GCP emulator is being used.


139-151:

✅ Verification successful

Good environment-aware testing for non-existent files.

The test appropriately uses environment variables to construct the test URL and correctly handles different error codes based on the testing environment.

Let's verify that the environment variable referenced is consistently used throughout the codebase:


🏁 Script executed:

#!/bin/bash
# Check usage of GCP_BUCKET_NAME environment variable
rg -A 3 "GCP_BUCKET_NAME" --type ts

Length of output: 2131


🏁 Script executed:

#!/bin/bash
# Display the implementation of verifyImageUrl to confirm error codes
rg -A 20 "verifyImageUrl" src/storage/gcloud-storage/gcp-storage.service.ts

Length of output: 950


🏁 Script executed:

#!/bin/bash
# Search for file-not-found constant usage in implementation
rg -C 5 "file-not-found" src/storage/gcloud-storage/gcp-storage.service.ts

Length of output: 751


Approve environment-aware error handling test

The non-existent file test correctly validates both emulator and production paths:

  • With GCP_STORAGE_EMULATOR_HOST set, verifyImageUrl returns invalid-url.
  • Without the emulator, it returns file-not-found.

No further changes needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants