Skip to content

Commit 1333bcb

Browse files
Set up Resource UI deployment to firebase (#1640)
1 parent dcc75fd commit 1333bcb

11 files changed

Lines changed: 175 additions & 25 deletions

File tree

.github/setup/action.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ runs:
3535
- run: pnpm ci --prefer-offline
3636
if: ${{ inputs.install-deps == 'true' && inputs.only-changed == 'false' }}
3737
shell: bash
38-
- run: pnpm --filter "...[origin/main]..." ci --prefer-offline
38+
# CHANGED_SINCE is set by the calling workflow's top-level env (previous main tip on a
39+
# push to main, origin/main otherwise); fall back to origin/main if it isn't provided.
40+
- run: pnpm --filter "...[${CHANGED_SINCE:-origin/main}]..." ci --prefer-offline
3941
if: ${{ inputs.install-deps == 'true' && inputs.only-changed == 'true' }}
4042
shell: bash

.github/workflows/ci.yml

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,24 @@ concurrency:
1111
group: ${{ github.workflow }} @ ${{ github.ref }}
1212
cancel-in-progress: true
1313

14+
env:
15+
# Diff base for pnpm --filter change detection
16+
CHANGED_SINCE: ${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') && github.event.before || 'origin/main' }}
17+
1418
jobs:
1519
build:
1620
runs-on: ubuntu-latest
1721
timeout-minutes: 10
1822
steps:
1923
- uses: actions/checkout@v6
24+
with:
25+
fetch-depth: 0
2026
- uses: ./.github/setup
2127
with:
2228
only-changed: true
2329
FONTAWESOME_NPM_AUTH_TOKEN: ${{ secrets.FONTAWESOME_NPM_AUTH_TOKEN }}
24-
- run: pnpm --filter "...[origin/main]..." --if-present codegen
25-
- run: pnpm --filter "...[origin/main]..." --if-present build
30+
- run: pnpm --filter "...[${{ env.CHANGED_SINCE }}]..." --if-present codegen
31+
- run: pnpm --filter "...[${{ env.CHANGED_SINCE }}]..." --if-present build
2632
- name: Archive production artifacts
2733
uses: actions/upload-artifact@v7
2834
with:
@@ -46,34 +52,40 @@ jobs:
4652
timeout-minutes: 10
4753
steps:
4854
- uses: actions/checkout@v6
55+
with:
56+
fetch-depth: 0
4957
- uses: ./.github/setup
5058
with:
5159
only-changed: true
5260
FONTAWESOME_NPM_AUTH_TOKEN: ${{ secrets.FONTAWESOME_NPM_AUTH_TOKEN }}
53-
- run: pnpm --filter "...[origin/main]..." --if-present codegen
54-
- run: pnpm --filter "...[origin/main]..." --if-present generate
55-
- run: pnpm --filter "...[origin/main]" --if-present lint:eslint
61+
- run: pnpm --filter "...[${{ env.CHANGED_SINCE }}]..." --if-present codegen
62+
- run: pnpm --filter "...[${{ env.CHANGED_SINCE }}]..." --if-present generate
63+
- run: pnpm --filter "...[${{ env.CHANGED_SINCE }}]" --if-present lint:eslint
5664
- run: pnpm lint
5765

5866
test:
5967
runs-on: ubuntu-latest
6068
timeout-minutes: 10
6169
steps:
6270
- uses: actions/checkout@v6
71+
with:
72+
fetch-depth: 0
6373
- uses: ./.github/setup
6474
with:
6575
only-changed: true
6676
FONTAWESOME_NPM_AUTH_TOKEN: ${{ secrets.FONTAWESOME_NPM_AUTH_TOKEN }}
6777
- run: pnpm exec playwright install chromium --only-shell
68-
- run: pnpm --filter "...[origin/main]..." --if-present codegen
69-
- run: pnpm --filter "...[origin/main]..." --if-present generate
70-
- run: pnpm --filter "...[origin/main]" --if-present test
78+
- run: pnpm --filter "...[${{ env.CHANGED_SINCE }}]..." --if-present codegen
79+
- run: pnpm --filter "...[${{ env.CHANGED_SINCE }}]..." --if-present generate
80+
- run: pnpm --filter "...[${{ env.CHANGED_SINCE }}]" --if-present test
7181

7282
e2e:
7383
timeout-minutes: 10
7484
runs-on: ubuntu-latest
7585
steps:
7686
- uses: actions/checkout@v6
87+
with:
88+
fetch-depth: 0
7789
- uses: ./.github/setup
7890
with:
7991
only-changed: true
@@ -87,13 +99,13 @@ jobs:
8799
run: |
88100
sudo echo "127.0.0.1 navigate.lucuma.xyz" | sudo tee -a /etc/hosts
89101
- run: pnpm exec playwright install firefox --only-shell
90-
- run: pnpm --filter "...@gemini-hlsw/navigate-e2e[origin/main]..." --if-present build
91-
- run: pnpm --filter "...@gemini-hlsw/navigate-e2e[origin/main]..." --if-present e2e:docker-up
102+
- run: pnpm --filter "...navigate-e2e[${{ env.CHANGED_SINCE }}]..." --if-present build
103+
- run: pnpm --filter "...navigate-e2e[${{ env.CHANGED_SINCE }}]..." --if-present e2e:docker-up
92104
env:
93105
LUCUMA_REFRESH_TOKEN: ${{ secrets.LUCUMA_DEV_API_KEY }}
94106

95107
- name: Run Playwright tests
96-
run: pnpm --filter "...@gemini-hlsw/navigate-e2e[origin/main]..." --if-present test:e2e
108+
run: pnpm --filter "...navigate-e2e[${{ env.CHANGED_SINCE }}]..." --if-present test:e2e
97109
env:
98110
LUCUMA_REFRESH_TOKEN: ${{ secrets.LUCUMA_DEV_API_KEY }}
99111
DATABASE_URL: 'postgresql://jimmy:banana@127.0.0.1:5432/configs'
@@ -265,3 +277,34 @@ jobs:
265277
env:
266278
HEROKU_API_KEY: ${{ secrets.HEROKU_API_KEY }}
267279
run: ./deploy/deploy-heroku.sh
280+
281+
deploy-resource:
282+
runs-on: ubuntu-latest
283+
if: (github.ref == 'refs/heads/main' && github.repository_owner == 'gemini-hlsw')
284+
timeout-minutes: 10
285+
environment:
286+
name: resource-ui-dev
287+
url: 'https://resource-dev.lucuma.xyz'
288+
steps:
289+
- uses: actions/checkout@v6
290+
with:
291+
fetch-depth: 0
292+
- uses: ./.github/setup
293+
with:
294+
only-changed: true
295+
FONTAWESOME_NPM_AUTH_TOKEN: ${{ secrets.FONTAWESOME_NPM_AUTH_TOKEN }}
296+
- run: pnpm --filter "...resource-ui[${{ env.CHANGED_SINCE }}]..." --if-present build
297+
298+
# Set env.DEPLOY_RESOURCE if there are changes
299+
- run: pnpm --filter "...resource-ui[${{ env.CHANGED_SINCE }}]..." --if-present ci:set-deploy-flag
300+
301+
- name: Deploy staging app to Firebase
302+
if: env.DEPLOY_RESOURCE == 'true'
303+
uses: FirebaseExtended/action-hosting-deploy@v0
304+
with:
305+
repoToken: ${{ secrets.GITHUB_TOKEN }}
306+
firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
307+
projectId: ${{ vars.FIREBASE_PROJECT_ID }}
308+
entryPoint: ./packages/resource-ui
309+
target: dev
310+
channelId: live

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ yarn-debug.log*
77
yarn-error.log*
88
pnpm-debug.log*
99
lerna-debug.log*
10+
firebase-debug.log*
11+
firebase-debug.*.log*
1012

1113
node_modules
1214
dist
1315
dist-ssr
1416
*.tsbuildinfo
1517
*.local
1618
pruned
19+
.firebase/
1720

1821
# Editor directories and files
1922
.idea

packages/common-ui/src/functions.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,13 @@ export function parseNumber<T extends number | string>(
9999
): T extends undefined ? number | undefined : number {
100100
return typeof value === 'string' ? parseFloat(value) : (value as T extends undefined ? number | undefined : number);
101101
}
102+
103+
/**
104+
* Converts a relative URI to an absolute URI based on the current window origin.
105+
*/
106+
export const withAbsoluteUri = (uri: string, isWs = false) => {
107+
if (!uri.startsWith('/')) return uri;
108+
109+
const newUri = window.location.origin + uri;
110+
return isWs ? newUri.replace(/^http/, 'ws') : newUri;
111+
};

packages/resource-ui/.firebaserc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"projects": {
3+
"default": "resource-ae0b7"
4+
},
5+
"targets": {
6+
"resource-ae0b7": {
7+
"hosting": {
8+
"dev": ["resource-ae0b7-dev"],
9+
"staging": ["resource-ae0b7-staging"],
10+
"production": ["resource-ae0b7"]
11+
}
12+
}
13+
}
14+
}

packages/resource-ui/firebase.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"hosting": [
3+
{
4+
"target": "dev",
5+
"public": "dist",
6+
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
7+
"rewrites": [
8+
{
9+
"source": "**",
10+
"destination": "/index.html"
11+
}
12+
]
13+
},
14+
{
15+
"target": "staging",
16+
"public": "dist",
17+
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
18+
"rewrites": [
19+
{
20+
"source": "**",
21+
"destination": "/index.html"
22+
}
23+
]
24+
},
25+
{
26+
"target": "production",
27+
"public": "dist",
28+
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
29+
"rewrites": [
30+
{
31+
"source": "**",
32+
"destination": "/index.html"
33+
}
34+
]
35+
}
36+
]
37+
}

packages/resource-ui/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"dev:mock-server": "node --watch --enable-source-maps ./mock-server/server.ts",
1515
"codegen": "graphql-codegen --config tasks/codegen.ts",
1616
"codegen:mock": "graphql-codegen --config tasks/codegen.mock.ts",
17+
"ci:set-deploy-flag": "echo \"DEPLOY_RESOURCE=true\" >> \"$GITHUB_ENV\"",
1718
"prebuild": "pnpm run codegen",
1819
"test": "vitest run",
1920
"build": "tsc -b && vite build",
Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,28 @@
11
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client';
2+
import { withAbsoluteUri } from '@gemini-hlsw/lucuma-common-ui';
3+
4+
const graphqlEndpoints = {
5+
'resource-ae0b7-dev.web.app': 'https://lucuma-resource-dev.lucuma.xyz/resource/graphql',
6+
'resource-dev.lucuma.xyz': 'https://lucuma-resource-dev.lucuma.xyz/resource/graphql',
7+
localhost: '/resource/graphql',
8+
9+
'resource-ae0b7-staging.web.app': 'https://lucuma-resource-staging.lucuma.xyz/resource/graphql',
10+
'resource-staging.lucuma.xyz': 'https://lucuma-resource-staging.lucuma.xyz/resource/graphql',
11+
12+
'resource-ae0b7.web.app': 'https://lucuma-resource-dev.lucuma.xyz/resource/graphql',
13+
'resource.gemini.edu': 'https://lucuma-resource-dev.lucuma.xyz/resource/graphql',
14+
} satisfies Record<string, string>;
15+
16+
const defaultGraphqlEndpoint = graphqlEndpoints.localhost;
17+
18+
const uri = graphqlEndpoints[window.location.hostname as keyof typeof graphqlEndpoints] ?? defaultGraphqlEndpoint;
219

320
// Create an Apollo Client instance with the specified GraphQL endpoint and cache configuration.
421
export const client = new ApolloClient({
5-
link: new HttpLink({
6-
uri: '/resource/graphql',
7-
}),
22+
clientAwareness: {
23+
name: 'resource-ui',
24+
version: import.meta.env.FRONTEND_VERSION,
25+
},
26+
link: new HttpLink({ uri: withAbsoluteUri(uri) }),
827
cache: new InMemoryCache(),
928
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// <reference types="vite/client" />
2+
3+
// Extra variables that will be replaced by Vite in the build process, defined in vite.config.ts
4+
interface ImportMetaEnv {
5+
readonly FRONTEND_VERSION: string;
6+
}
7+
8+
interface ImportMeta {
9+
readonly env: ImportMetaEnv;
10+
}

packages/resource-ui/vite.config.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,29 @@ import babel from '@rolldown/plugin-babel';
22
import tailwindcss from '@tailwindcss/vite';
33
import react, { reactCompilerPreset } from '@vitejs/plugin-react';
44
import { playwright } from '@vitest/browser-playwright';
5+
import { execSync } from 'child_process';
56
import { defineConfig } from 'vitest/config';
67

8+
import pkgJson from './package.json' with { type: 'json' };
9+
10+
const version = (process.env.GITHUB_REF_NAME || `v${pkgJson.version}`).trim();
11+
const commitHash = (process.env.GITHUB_SHA || execSync('git rev-parse --short HEAD').toString()).trim().slice(0, 7);
12+
13+
const buildTime = new Date();
14+
function formatDate(date: Date) {
15+
const years = date.getFullYear();
16+
// Months are 0-indexed
17+
const months = date.getMonth() + 1;
18+
const days = date.getDate();
19+
return `${years}${months.toString().padStart(2, '0')}${days.toString().padStart(2, '0')}`;
20+
}
21+
const frontendVersion = `${version}+${formatDate(buildTime)}.${commitHash}`;
22+
723
// https://vite.dev/config/
824
export default defineConfig({
25+
define: {
26+
'import.meta.env.FRONTEND_VERSION': JSON.stringify(frontendVersion),
27+
},
928
css: {
1029
transformer: 'lightningcss',
1130
lightningcss: {
@@ -28,6 +47,7 @@ export default defineConfig({
2847
tailwindcss(),
2948
],
3049
server: {
50+
allowedHosts: ['localhost', '.lucuma.xyz', '.gemini.edu'],
3151
proxy: {
3252
'/resource/graphql': {
3353
target: 'https://lucuma-resource-dev.lucuma.xyz',

0 commit comments

Comments
 (0)