diff --git a/.github/workflows/frontend-deploy.yml b/.github/workflows/frontend-deploy.yml
index 26153ef9..cf6f8eff 100644
--- a/.github/workflows/frontend-deploy.yml
+++ b/.github/workflows/frontend-deploy.yml
@@ -13,12 +13,16 @@ on:
- '**/wrangler.jsonc'
- '**/pnpm-*.yaml'
- '.github/workflows/frontend-deploy.yml'
- pull_request:
workflow_dispatch:
+ workflow_call:
+ inputs:
+ environment:
+ required: true
+ type: string
+ description: 'The environment to deploy to (staging-preview or production-preview)'
jobs:
deploy:
- if: github.repository_owner == 'modrinth'
runs-on: ubuntu-latest
permissions:
contents: read
@@ -34,15 +38,28 @@ jobs:
id: meta
run: |
echo "cmd=deploy" >> $GITHUB_OUTPUT
- if [ "${{ github.ref }}" == "refs/heads/main" ]; then
+
+ ENV_INPUT="${{ inputs.environment }}"
+ REF="${{ github.ref }}"
+ SHA_SHORT="${GITHUB_SHA::8}"
+
+ if [ "$ENV_INPUT" = "staging-preview" ]; then
+ echo "env=staging" >> $GITHUB_OUTPUT
+ echo "url=https://git-$SHA_SHORT-frontend-staging.modrinth.workers.dev" >> $GITHUB_OUTPUT
+ echo "cmd=versions upload --preview-alias git-$SHA_SHORT --var PREVIEW:true" >> $GITHUB_OUTPUT
+
+ elif [ "$ENV_INPUT" = "production-preview" ]; then
+ echo "env=production" >> $GITHUB_OUTPUT
+ echo "url=https://git-$SHA_SHORT-frontend.modrinth.workers.dev" >> $GITHUB_OUTPUT
+ echo "cmd=versions upload --preview-alias git-$SHA_SHORT --var PREVIEW:true" >> $GITHUB_OUTPUT
+
+ elif [ "$REF" = "refs/heads/main" ]; then
echo "env=staging" >> $GITHUB_OUTPUT
echo "url=https://staging.modrinth.com" >> $GITHUB_OUTPUT
- elif [ "${{ github.ref }}" != "refs/heads/prod" ] && [ "${{ github.ref }}" != "refs/heads/main" ]; then
- echo "env=staging" >> $GITHUB_OUTPUT
- echo "url=https://git-${GITHUB_SHA::8}-frontend-staging.modrinth.workers.dev" >> $GITHUB_OUTPUT
- echo "cmd=versions upload --preview-alias git-${GITHUB_SHA::8} --var PREVIEW:true" >> $GITHUB_OUTPUT
+
else
- # Production env should be empty
+ # Production env (no preview)
+ echo "env=production" >> $GITHUB_OUTPUT
echo "url=https://modrinth.com" >> $GITHUB_OUTPUT
fi
@@ -77,6 +94,8 @@ jobs:
CF_PAGES_BRANCH: ${{ github.ref_name }}
CF_PAGES_COMMIT_SHA: ${{ github.sha }}
CF_PAGES_URL: ${{ steps.meta.outputs.url }}
+ BUILD_ENV: ${{ steps.meta.outputs.env }}
+ PREVIEW: ${{ inputs.environment != '' && 'true' || 'false' }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
- name: Create Sentry release and upload sourcemaps
@@ -86,7 +105,7 @@ jobs:
SENTRY_ORG: modrinth
SENTRY_PROJECT: knossos-server
with:
- environment: ${{ steps.meta.outputs.env || 'production' }}
+ environment: ${{ steps.meta.outputs.env }}
sourcemaps: ./apps/frontend/.output/server
url_prefix: '~/'
@@ -96,7 +115,7 @@ jobs:
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
accountId: ${{ secrets.CF_ACCOUNT_ID }}
- environment: ${{ steps.meta.outputs.env }}
+ environment: ${{ steps.meta.outputs.env != 'production' && steps.meta.outputs.env || '' }}
workingDirectory: ./apps/frontend
packageManager: pnpm
wranglerVersion: '4.54.0'
@@ -111,15 +130,14 @@ jobs:
--data '{"hosts": ["modrinth.com", "www.modrinth.com", "staging.modrinth.com"]}' \
https://api.cloudflare.com/client/v4/zones/e39df17b9c4ef44cbce2646346ee6d33/purge_cache
- - name: Comment deploy URL on PR
- if: github.event_name == 'pull_request'
- uses: peter-evans/create-or-update-comment@v4
- with:
- issue-number: ${{ github.event.pull_request.number }}
- body: |
- ## 🚀 Frontend Deploy
+ - name: Write deployment URL to file
+ if: ${{ inputs.environment != '' }}
+ run: |
+ echo "${{ steps.meta.outputs.url }}" > deployment-url-${{ inputs.environment }}.txt
- | Commit | URL |
- |--------|-----|
- | ${{ github.event.pull_request.head.sha }} | ${{ steps.wrangler.outputs.deployment-url }} |
- comment-tag: frontend-deploy
+ - name: Upload deployment URL
+ if: ${{ inputs.environment != '' }}
+ uses: actions/upload-artifact@v6
+ with:
+ name: deployment-url-${{ inputs.environment }}
+ path: deployment-url-${{ inputs.environment }}.txt
diff --git a/.github/workflows/frontend-preview.yml b/.github/workflows/frontend-preview.yml
new file mode 100644
index 00000000..e75a7122
--- /dev/null
+++ b/.github/workflows/frontend-preview.yml
@@ -0,0 +1,72 @@
+name: Deploy frontend preview
+
+on:
+ pull_request:
+ paths:
+ - 'apps/frontend/**/*'
+ - 'packages/ui/**/*'
+ - 'packages/utils/**/*'
+ - 'packages/assets/**/*'
+ - '**/wrangler.jsonc'
+ - '**/pnpm-*.yaml'
+ - '.github/workflows/frontend-preview.yml'
+
+jobs:
+ deploy:
+ if: github.repository_owner == 'modrinth' && github.event.pull_request.head.repo.full_name == github.repository
+ uses: ./.github/workflows/frontend-deploy.yml
+ secrets: inherit
+ strategy:
+ matrix:
+ environment: [staging-preview, production-preview]
+ with:
+ environment: ${{ matrix.environment }}
+
+ comment:
+ if: github.repository_owner == 'modrinth' && github.event.pull_request.head.repo.full_name == github.repository
+ runs-on: ubuntu-latest
+ needs: deploy
+ steps:
+ - name: Download deployment URLs
+ uses: actions/download-artifact@v7
+ with:
+ pattern: deployment-url-*
+ merge-multiple: true
+
+ - name: Read deployment URLs
+ id: urls
+ run: |
+ STAGING_PREVIEW_URL=$(cat deployment-url-staging-preview.txt)
+ PRODUCTION_PREVIEW_URL=$(cat deployment-url-production-preview.txt)
+
+ echo "Production preview URL: $PRODUCTION_PREVIEW_URL"
+ echo "Staging preview URL: $STAGING_PREVIEW_URL"
+
+ echo "staging-preview-url=$STAGING_PREVIEW_URL" >> $GITHUB_OUTPUT
+ echo "production-preview-url=$PRODUCTION_PREVIEW_URL" >> $GITHUB_OUTPUT
+
+ - name: Find comment
+ if: github.event_name == 'pull_request'
+ uses: peter-evans/find-comment@v3
+ id: fc
+ with:
+ issue-number: ${{ github.event.pull_request.number }}
+ comment-author: 'github-actions[bot]'
+ body-includes: Frontend previews
+
+ - name: Comment deploy URL on PR
+ if: github.event_name == 'pull_request'
+ uses: peter-evans/create-or-update-comment@v5
+ with:
+ issue-number: ${{ github.event.pull_request.number }}
+ comment-id: ${{ steps.fc.outputs.comment-id }}
+ body: |
+ ## Frontend previews
+
+ Last deployed commit is [${{ github.sha }}](${{ github.event.pull_request.head.repo.html_url }}/commit/${{ github.sha }})
+
+ | Environment | URL |
+ |-------------|-----|
+ | staging | ${{ steps.urls.outputs.staging-preview-url }} |
+ | production | ${{ steps.urls.outputs.production-preview-url }} |
+ edit-mode: replace
diff --git a/apps/frontend/nuxt.config.ts b/apps/frontend/nuxt.config.ts
index 7a7e16c8..93afe78c 100644
--- a/apps/frontend/nuxt.config.ts
+++ b/apps/frontend/nuxt.config.ts
@@ -187,6 +187,8 @@ export default defineNuxtConfig({
pyroBaseUrl: process.env.PYRO_BASE_URL,
siteUrl: getDomain(),
production: isProduction(),
+ buildEnv: process.env.BUILD_ENV,
+ preview: process.env.PREVIEW === 'true',
featureFlagOverrides: getFeatureFlagOverrides(),
owner: process.env.VERCEL_GIT_REPO_OWNER || 'modrinth',
@@ -253,6 +255,7 @@ export default defineNuxtConfig({
},
replace: {
__SENTRY_RELEASE__: JSON.stringify(process.env.CF_PAGES_COMMIT_SHA || 'unknown'),
+ __SENTRY_ENVIRONMENT__: JSON.stringify(process.env.BUILD_ENV || 'development'),
},
},
devtools: {
diff --git a/apps/frontend/src/components/ui/ModrinthFooter.vue b/apps/frontend/src/components/ui/ModrinthFooter.vue
index 39283653..a641d109 100644
--- a/apps/frontend/src/components/ui/ModrinthFooter.vue
+++ b/apps/frontend/src/components/ui/ModrinthFooter.vue
@@ -1,6 +1,7 @@
+
+
+
+
+ {{ formatMessage(messages.title) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ unknown
+
+ {{ config.public.hash }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/frontend/src/composables/featureFlags.ts b/apps/frontend/src/composables/featureFlags.ts
index 92798d9c..d7f5b721 100644
--- a/apps/frontend/src/composables/featureFlags.ts
+++ b/apps/frontend/src/composables/featureFlags.ts
@@ -42,22 +42,7 @@ export const DEFAULT_FEATURE_FLAGS = validateValues({
hideRussiaCensorshipBanner: false,
serverDiscovery: false,
disablePrettyProjectUrlRedirects: false,
- // advancedRendering: true,
- // externalLinksNewTab: true,
- // notUsingBlockers: false,
- // hideModrinthAppPromos: false,
- // preferredDarkTheme: 'dark',
- // hideStagingBanner: false,
-
- // Project display modes
- // modSearchDisplayMode: 'list',
- // pluginSearchDisplayMode: 'list',
- // resourcePackSearchDisplayMode: 'gallery',
- // modpackSearchDisplayMode: 'list',
- // shaderSearchDisplayMode: 'gallery',
- // dataPackSearchDisplayMode: 'list',
- // userProjectDisplayMode: 'list',
- // collectionProjectDisplayMode: 'list',
+ hidePreviewBanner: false,
} as const)
export type FeatureFlag = keyof typeof DEFAULT_FEATURE_FLAGS
diff --git a/apps/frontend/src/layouts/default.vue b/apps/frontend/src/layouts/default.vue
index 10456d75..b156ddbd 100644
--- a/apps/frontend/src/layouts/default.vue
+++ b/apps/frontend/src/layouts/default.vue
@@ -47,6 +47,7 @@
route.path !== '/settings/billing'
"
/>
+
https://modrinth.com. This preview deploy is used by Modrinth staff for testing purposes. It was built using {owner}/{branch} @ {commit}."
+ },
+ "layout.banner.preview.title": {
+ "message": "This is a preview deploy of the Modrinth website."
+ },
"layout.banner.staging.description": {
"message": "The staging environment is completely separate from the production Modrinth database. This is used for testing and debugging purposes, and may be running in-development versions of the Modrinth backend or frontend newer than the production instance."
},
diff --git a/apps/frontend/src/server/plugins/sentry-cloudflare-plugin.ts b/apps/frontend/src/server/plugins/sentry-cloudflare-plugin.ts
index 1bcb0ab1..4f103424 100644
--- a/apps/frontend/src/server/plugins/sentry-cloudflare-plugin.ts
+++ b/apps/frontend/src/server/plugins/sentry-cloudflare-plugin.ts
@@ -1,11 +1,13 @@
import { sentryCloudflareNitroPlugin } from '@sentry/nuxt/module/plugins'
declare const __SENTRY_RELEASE__: string
+declare const __SENTRY_ENVIRONMENT__: string
export default defineNitroPlugin(
sentryCloudflareNitroPlugin({
dsn: 'https://9cf8f56ab7055ab6b1042fad535f2a44@o485889.ingest.us.sentry.io/4510709722185728',
tracesSampleRate: 0.0001, // match with wrangler.jsonc
release: __SENTRY_RELEASE__,
+ environment: __SENTRY_ENVIRONMENT__,
}),
)
diff --git a/packages/ui/src/components/base/AutoLink.vue b/packages/ui/src/components/base/AutoLink.vue
index 36fd26a7..192c9aa8 100644
--- a/packages/ui/src/components/base/AutoLink.vue
+++ b/packages/ui/src/components/base/AutoLink.vue
@@ -1,8 +1,8 @@
-
+
-
+
diff --git a/turbo.jsonc b/turbo.jsonc
index aec2b343..dabc927b 100644
--- a/turbo.jsonc
+++ b/turbo.jsonc
@@ -15,6 +15,8 @@
"NODE_ENV",
"SITE_URL",
"BASE_URL",
+ "PREVIEW",
+ "BUILD_ENV",
"FLAG_OVERRIDES",
"BROWSER_BASE_URL",
"RATE_LIMIT_IGNORE_KEY",
@@ -32,7 +34,9 @@
"RUST_*",
"RUSTFLAGS",
"FORCE_COLOR",
- "NEXTEST_*"
+ "NEXTEST_*",
+ "BUILD_ENV",
+ "PREVIEW"
]
},
"lint": {