Merged in chore/release-pipeline (pull request #3352)
Add scripts for handling deployments Approved-by: Linus Flood
This commit is contained in:
@@ -47,6 +47,7 @@ For more details see the respective apps and packages' README files.
|
|||||||
|
|
||||||
## More documentation
|
## More documentation
|
||||||
|
|
||||||
|
- [Deploy](./docs/deploy.md)
|
||||||
- [Icons](./docs/icons.md)
|
- [Icons](./docs/icons.md)
|
||||||
- [Payment](./docs/payment.md)
|
- [Payment](./docs/payment.md)
|
||||||
- [Translations (i18n)](./docs/translations.md)
|
- [Translations (i18n)](./docs/translations.md)
|
||||||
|
|||||||
2
apps/partner-sas/env/client.ts
vendored
2
apps/partner-sas/env/client.ts
vendored
@@ -5,11 +5,13 @@ export const env = createEnv({
|
|||||||
client: {
|
client: {
|
||||||
NEXT_PUBLIC_SENTRY_ENVIRONMENT: z.string().default("development"),
|
NEXT_PUBLIC_SENTRY_ENVIRONMENT: z.string().default("development"),
|
||||||
NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE: z.coerce.number().default(0.001),
|
NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE: z.coerce.number().default(0.001),
|
||||||
|
NEXT_PUBLIC_RELEASE_TAG: z.string().optional(),
|
||||||
},
|
},
|
||||||
emptyStringAsUndefined: true,
|
emptyStringAsUndefined: true,
|
||||||
runtimeEnv: {
|
runtimeEnv: {
|
||||||
NEXT_PUBLIC_SENTRY_ENVIRONMENT: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT,
|
NEXT_PUBLIC_SENTRY_ENVIRONMENT: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT,
|
||||||
NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE:
|
NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE:
|
||||||
process.env.NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE,
|
process.env.NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE,
|
||||||
|
NEXT_PUBLIC_RELEASE_TAG: process.env.NEXT_PUBLIC_RELEASE_TAG,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
2
apps/partner-sas/env/server.ts
vendored
2
apps/partner-sas/env/server.ts
vendored
@@ -36,6 +36,7 @@ export const env = createEnv({
|
|||||||
.refine((s) => s === "true" || s === "false")
|
.refine((s) => s === "true" || s === "false")
|
||||||
.transform((s) => s === "true")
|
.transform((s) => s === "true")
|
||||||
.default("false"),
|
.default("false"),
|
||||||
|
RELEASE_TAG: z.string().optional(),
|
||||||
},
|
},
|
||||||
emptyStringAsUndefined: true,
|
emptyStringAsUndefined: true,
|
||||||
runtimeEnv: {
|
runtimeEnv: {
|
||||||
@@ -52,5 +53,6 @@ export const env = createEnv({
|
|||||||
SENTRY_ENVIRONMENT: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT,
|
SENTRY_ENVIRONMENT: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT,
|
||||||
SENTRY_SERVER_SAMPLERATE: process.env.SENTRY_SERVER_SAMPLERATE,
|
SENTRY_SERVER_SAMPLERATE: process.env.SENTRY_SERVER_SAMPLERATE,
|
||||||
REDEMPTION_ENABLED: process.env.REDEMPTION_ENABLED,
|
REDEMPTION_ENABLED: process.env.REDEMPTION_ENABLED,
|
||||||
|
RELEASE_TAG: process.env.NEXT_PUBLIC_RELEASE_TAG,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ Sentry.init({
|
|||||||
denyUrls: denyUrls,
|
denyUrls: denyUrls,
|
||||||
// Disable logs for clients, will probably give us too much noise
|
// Disable logs for clients, will probably give us too much noise
|
||||||
enableLogs: false,
|
enableLogs: false,
|
||||||
|
release: env.NEXT_PUBLIC_RELEASE_TAG || undefined,
|
||||||
beforeSendLog(log) {
|
beforeSendLog(log) {
|
||||||
const ignoredLevels: (typeof log.level)[] = ["debug", "trace", "info"]
|
const ignoredLevels: (typeof log.level)[] = ["debug", "trace", "info"]
|
||||||
if (ignoredLevels.includes(log.level)) {
|
if (ignoredLevels.includes(log.level)) {
|
||||||
|
|||||||
@@ -21,5 +21,6 @@ async function configureSentry() {
|
|||||||
tracesSampleRate: env.SENTRY_SERVER_SAMPLERATE,
|
tracesSampleRate: env.SENTRY_SERVER_SAMPLERATE,
|
||||||
denyUrls: denyUrls,
|
denyUrls: denyUrls,
|
||||||
enableLogs: true,
|
enableLogs: true,
|
||||||
|
release: env.RELEASE_TAG || undefined,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
[build]
|
[build]
|
||||||
command = "yarn test --filter=@scandic-hotels/partner-sas && yarn build:sas"
|
command = "export NEXT_PUBLIC_RELEASE_TAG=$(git tag -l 'release-v*' | sort -V | tail -n 1) && yarn test --filter=@scandic-hotels/partner-sas && yarn build:sas"
|
||||||
publish = "apps/partner-sas/.next"
|
publish = "apps/partner-sas/.next"
|
||||||
|
|
||||||
ignore = "if [ -z ${CACHED_COMMIT_REF+x} ] ; then echo 'no CACHED_COMMIT_REF found' && false ; else git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF apps/partner-sas packages/booking-flow packages/common packages/trpc packages/design-system packages/typescript-config ; fi"
|
ignore = "if [ -z ${CACHED_COMMIT_REF+x} ] ; then echo 'no CACHED_COMMIT_REF found' && false ; else git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF apps/partner-sas packages/booking-flow packages/common packages/trpc packages/design-system packages/typescript-config ; fi"
|
||||||
|
|
||||||
[context.branch-deploy]
|
[context.branch-deploy]
|
||||||
command = "yarn test --filter=@scandic-hotels/partner-sas && yarn build:sas"
|
command = "export NEXT_PUBLIC_RELEASE_TAG=$(git tag -l 'release-v*' | sort -V | tail -n 1) && yarn test --filter=@scandic-hotels/partner-sas && yarn build:sas"
|
||||||
|
|
||||||
[context.deploy-preview]
|
[context.deploy-preview]
|
||||||
command = "yarn test --filter=@scandic-hotels/partner-sas && yarn build:sas"
|
command = "export NEXT_PUBLIC_RELEASE_TAG=$(git tag -l 'release-v*' | sort -V | tail -n 1) && yarn test --filter=@scandic-hotels/partner-sas && yarn build:sas"
|
||||||
|
|
||||||
[build.environment]
|
[build.environment]
|
||||||
# set TERM variable for terminal output
|
# set TERM variable for terminal output
|
||||||
|
|||||||
@@ -27,11 +27,17 @@ export function EnvironmentWatermark() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { environment, name } = getEnvironmentName()
|
const { environment, name } = getEnvironmentName()
|
||||||
const displayValue = name === environment ? name : `${name} (${environment})`
|
const displayValues = [name]
|
||||||
|
if (name !== environment) {
|
||||||
|
displayValues.push(`(${environment})`)
|
||||||
|
}
|
||||||
|
if (env.NEXT_PUBLIC_RELEASE_TAG) {
|
||||||
|
displayValues.push(`[${env.NEXT_PUBLIC_RELEASE_TAG}]`)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={variants({ environment: environment })}>
|
<div className={variants({ environment: environment })}>
|
||||||
<span>{displayValue}</span>
|
<span>{displayValues.join(" ")}</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
2
apps/scandic-web/env/client.ts
vendored
2
apps/scandic-web/env/client.ts
vendored
@@ -8,6 +8,7 @@ export const env = createEnv({
|
|||||||
NEXT_PUBLIC_SENTRY_ENVIRONMENT: z.string().default("development"),
|
NEXT_PUBLIC_SENTRY_ENVIRONMENT: z.string().default("development"),
|
||||||
NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE: z.coerce.number().default(0.001),
|
NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE: z.coerce.number().default(0.001),
|
||||||
NEXT_PUBLIC_PUBLIC_URL: z.string().optional(),
|
NEXT_PUBLIC_PUBLIC_URL: z.string().optional(),
|
||||||
|
NEXT_PUBLIC_RELEASE_TAG: z.string().optional(),
|
||||||
},
|
},
|
||||||
emptyStringAsUndefined: true,
|
emptyStringAsUndefined: true,
|
||||||
runtimeEnv: {
|
runtimeEnv: {
|
||||||
@@ -17,5 +18,6 @@ export const env = createEnv({
|
|||||||
NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE:
|
NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE:
|
||||||
process.env.NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE,
|
process.env.NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE,
|
||||||
NEXT_PUBLIC_PUBLIC_URL: process.env.NEXT_PUBLIC_PUBLIC_URL,
|
NEXT_PUBLIC_PUBLIC_URL: process.env.NEXT_PUBLIC_PUBLIC_URL,
|
||||||
|
NEXT_PUBLIC_RELEASE_TAG: process.env.NEXT_PUBLIC_RELEASE_TAG,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
2
apps/scandic-web/env/server.ts
vendored
2
apps/scandic-web/env/server.ts
vendored
@@ -112,6 +112,7 @@ export const env = createEnv({
|
|||||||
.refine((s) => s === "true" || s === "false")
|
.refine((s) => s === "true" || s === "false")
|
||||||
.transform((s) => s === "true")
|
.transform((s) => s === "true")
|
||||||
.default("false"),
|
.default("false"),
|
||||||
|
RELEASE_TAG: z.string().optional(),
|
||||||
},
|
},
|
||||||
emptyStringAsUndefined: true,
|
emptyStringAsUndefined: true,
|
||||||
runtimeEnv: {
|
runtimeEnv: {
|
||||||
@@ -168,5 +169,6 @@ export const env = createEnv({
|
|||||||
NEW_STAYS_ON_MY_PAGES: process.env.NEW_STAYS_ON_MY_PAGES,
|
NEW_STAYS_ON_MY_PAGES: process.env.NEW_STAYS_ON_MY_PAGES,
|
||||||
SEO_INERT: process.env.SEO_INERT,
|
SEO_INERT: process.env.SEO_INERT,
|
||||||
ENABLE_PROFILE_CONSENT: process.env.ENABLE_PROFILE_CONSENT,
|
ENABLE_PROFILE_CONSENT: process.env.ENABLE_PROFILE_CONSENT,
|
||||||
|
RELEASE_TAG: process.env.NEXT_PUBLIC_RELEASE_TAG,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ Sentry.init({
|
|||||||
denyUrls: denyUrls,
|
denyUrls: denyUrls,
|
||||||
// Disable logs for clients, will probably give us too much noise
|
// Disable logs for clients, will probably give us too much noise
|
||||||
enableLogs: false,
|
enableLogs: false,
|
||||||
|
release: env.NEXT_PUBLIC_RELEASE_TAG || undefined,
|
||||||
beforeSendLog(log) {
|
beforeSendLog(log) {
|
||||||
const ignoredLevels: (typeof log.level)[] = ["debug", "trace", "info"]
|
const ignoredLevels: (typeof log.level)[] = ["debug", "trace", "info"]
|
||||||
if (ignoredLevels.includes(log.level)) {
|
if (ignoredLevels.includes(log.level)) {
|
||||||
|
|||||||
@@ -22,5 +22,6 @@ async function configureSentry() {
|
|||||||
denyUrls: denyUrls,
|
denyUrls: denyUrls,
|
||||||
enableLogs: true,
|
enableLogs: true,
|
||||||
enableMetrics: true,
|
enableMetrics: true,
|
||||||
|
release: env.RELEASE_TAG || undefined,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
[build]
|
[build]
|
||||||
command = "yarn test --filter=@scandic-hotels/scandic-web && yarn build:web"
|
command = "export NEXT_PUBLIC_RELEASE_TAG=$(git tag -l 'release-v*' | sort -V | tail -n 1) && yarn test --filter=@scandic-hotels/scandic-web && yarn build:web"
|
||||||
publish = "apps/scandic-web/.next"
|
publish = "apps/scandic-web/.next"
|
||||||
|
|
||||||
ignore = "if [ -z ${CACHED_COMMIT_REF+x} ] ; then echo 'no CACHED_COMMIT_REF found' && false ; else git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF apps/scandic-web packages/booking-flow packages/common packages/trpc packages/design-system packages/typescript-config ; fi"
|
ignore = "if [ -z ${CACHED_COMMIT_REF+x} ] ; then echo 'no CACHED_COMMIT_REF found' && false ; else git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF apps/scandic-web packages/booking-flow packages/common packages/trpc packages/design-system packages/typescript-config ; fi"
|
||||||
|
|
||||||
[context.branch-deploy]
|
[context.branch-deploy]
|
||||||
command = "yarn test --filter=@scandic-hotels/scandic-web && yarn build:web"
|
command = "export NEXT_PUBLIC_RELEASE_TAG=$(git tag -l 'release-v*' | sort -V | tail -n 1) && yarn test --filter=@scandic-hotels/scandic-web && yarn build:web"
|
||||||
|
|
||||||
[context.deploy-preview]
|
[context.deploy-preview]
|
||||||
command = "yarn test --filter=@scandic-hotels/scandic-web && yarn build:web"
|
command = "export NEXT_PUBLIC_RELEASE_TAG=$(git tag -l 'release-v*' | sort -V | tail -n 1) && yarn test --filter=@scandic-hotels/scandic-web && yarn build:web"
|
||||||
|
|
||||||
[[plugins]]
|
[[plugins]]
|
||||||
package = "@netlify/plugin-nextjs"
|
package = "@netlify/plugin-nextjs"
|
||||||
|
|||||||
29
docs/deploy.md
Normal file
29
docs/deploy.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
## Deployment Script
|
||||||
|
|
||||||
|
This script automates the deployment process for the application by force-pushing the current branch to specific environment branches.
|
||||||
|
Deploying to production must be done via a release-branch
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
Be situated on the branch you want to deploy and then run the script using `yarn deploy:<environment>`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn deploy:stage
|
||||||
|
```
|
||||||
|
|
||||||
|
or if you want to explicitly call it by using `yarn dlx tsx scripts/deploy/deploy.ts` (or `bun`/`npx tsx`)
|
||||||
|
|
||||||
|
### Environments
|
||||||
|
|
||||||
|
| Environment | Target Branch | Description |
|
||||||
|
| :---------- | :------------ | :----------------------------------------- |
|
||||||
|
| `test` | `test` | Deploys to the test environment. |
|
||||||
|
| `stage` | `stage` | Deploys to the staging environment. |
|
||||||
|
| `preprod` | `prod` | Deploys to the pre-production environment. |
|
||||||
|
| `prod` | `release` | Deploys to the production environment. |
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- **Branch Validation**: Checks if the target environment is valid.
|
||||||
|
- **Tagging**: If deploying from a release branch (e.g., `release-v1.2.3`), it automatically creates and pushes a git tag (e.g., `v1.2.3`) if it doesn't exist.
|
||||||
|
- **Safety Check**: Prompts for confirmation before deploying.
|
||||||
113
package.json
113
package.json
@@ -1,57 +1,60 @@
|
|||||||
{
|
{
|
||||||
"name": "scandic",
|
"name": "scandic",
|
||||||
"packageManager": "yarn@4.6.0",
|
"packageManager": "yarn@4.6.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "turbo run build --env-mode=loose",
|
"build": "turbo run build --env-mode=loose",
|
||||||
"build:web": "turbo run build --filter=@scandic-hotels/scandic-web --env-mode=loose",
|
"build:web": "turbo run build --filter=@scandic-hotels/scandic-web --env-mode=loose",
|
||||||
"build:sas": "turbo run build --filter=@scandic-hotels/partner-sas --env-mode=loose",
|
"build:sas": "turbo run build --filter=@scandic-hotels/partner-sas --env-mode=loose",
|
||||||
"lint": "turbo run lint",
|
"lint": "turbo run lint",
|
||||||
"dev": "turbo run dev --output-logs new-only",
|
"dev": "turbo run dev --output-logs new-only",
|
||||||
"dev:web": "turbo run dev --filter=@scandic-hotels/scandic-web --output-logs new-only",
|
"dev:web": "turbo run dev --filter=@scandic-hotels/scandic-web --output-logs new-only",
|
||||||
"dev:ds": "turbo run dev --filter=@scandic-hotels/design-system --output-logs new-only",
|
"dev:ds": "turbo run dev --filter=@scandic-hotels/design-system --output-logs new-only",
|
||||||
"dev:sas": "turbo run dev --filter=@scandic-hotels/partner-sas --output-logs new-only",
|
"dev:sas": "turbo run dev --filter=@scandic-hotels/partner-sas --output-logs new-only",
|
||||||
"test": "turbo run test",
|
"test": "turbo run test",
|
||||||
"format": "turbo run format",
|
"format": "turbo run format",
|
||||||
"postinstall": "husky",
|
"postinstall": "husky",
|
||||||
"icons:update": "jiti scripts/material-symbols-update.mts",
|
"icons:update": "jiti scripts/material-symbols-update.mts",
|
||||||
"check-types": "turbo run check-types",
|
"check-types": "turbo run check-types",
|
||||||
"env:web": "node scripts/show-env.mjs scandic-web --missing",
|
"env:web": "node scripts/show-env.mjs scandic-web --missing",
|
||||||
"env:sas": "node scripts/show-env.mjs partner-sas --missing",
|
"env:sas": "node scripts/show-env.mjs partner-sas --missing",
|
||||||
"i18n:extract": "formatjs extract \"{apps/scandic-web,apps/partner-sas,packages/booking-flow,packages/design-system}/{actions,app,components,constants,contexts,env,hooks,i18n,lib,middlewares,netlify,providers,server,services,stores,utils}/**/*.{ts,tsx}\" --format scripts/i18n/formatter.mjs --out-file scripts/i18n/extracted.json",
|
"i18n:extract": "formatjs extract \"{apps/scandic-web,apps/partner-sas,packages/booking-flow,packages/design-system}/{actions,app,components,constants,contexts,env,hooks,i18n,lib,middlewares,netlify,providers,server,services,stores,utils}/**/*.{ts,tsx}\" --format scripts/i18n/formatter.mjs --out-file scripts/i18n/extracted.json",
|
||||||
"i18n:upload": "jiti scripts/i18n/upload.ts",
|
"i18n:upload": "jiti scripts/i18n/upload.ts",
|
||||||
"i18n:download": "jiti scripts/i18n/download.ts",
|
"i18n:download": "jiti scripts/i18n/download.ts",
|
||||||
"i18n:compile": "formatjs compile-folder --ast --format scripts/i18n/formatter.mjs scripts/i18n/translations-all scripts/i18n/dictionaries",
|
"i18n:compile": "formatjs compile-folder --ast --format scripts/i18n/formatter.mjs scripts/i18n/translations-all scripts/i18n/dictionaries",
|
||||||
"i18n:diff": "yarn i18n:extract && yarn i18n:pull && node scripts/i18n/diff.mjs",
|
"i18n:diff": "yarn i18n:extract && yarn i18n:pull && node scripts/i18n/diff.mjs",
|
||||||
"i18n:clean": "jiti scripts/i18n/clean.ts",
|
"i18n:clean": "jiti scripts/i18n/clean.ts",
|
||||||
"i18n:distribute": "jiti scripts/i18n/distribute.ts scandic-web partner-sas",
|
"i18n:distribute": "jiti scripts/i18n/distribute.ts scandic-web partner-sas",
|
||||||
"i18n:push": "yarn i18n:extract && yarn i18n:upload",
|
"i18n:push": "yarn i18n:extract && yarn i18n:upload",
|
||||||
"i18n:pull": "yarn i18n:download && yarn i18n:compile && yarn i18n:distribute",
|
"i18n:pull": "yarn i18n:download && yarn i18n:compile && yarn i18n:distribute",
|
||||||
"i18n:sync": "yarn i18n:push && yarn i18n:pull",
|
"i18n:sync": "yarn i18n:push && yarn i18n:pull",
|
||||||
"i18n:syncDefaultMessage": "yarn i18n:download && bun scripts/i18n/syncDefaultMessage/index.ts scripts/i18n/translations/en.json '{apps,packages}/**/*.{tsx,ts}' && yarn format --force"
|
"i18n:syncDefaultMessage": "yarn i18n:download && bun scripts/i18n/syncDefaultMessage/index.ts scripts/i18n/translations/en.json '{apps,packages}/**/*.{tsx,ts}' && yarn format --force",
|
||||||
},
|
"deploy:stage": "yarn dlx tsx scripts/deploy/deploy.ts stage",
|
||||||
"workspaces": [
|
"deploy:preprod": "yarn dlx tsx scripts/deploy/deploy.ts preprod",
|
||||||
"apps/*",
|
"deploy:prod": "yarn dlx tsx scripts/deploy/deploy.ts prod"
|
||||||
"packages/*"
|
},
|
||||||
],
|
"workspaces": [
|
||||||
"devDependencies": {
|
"apps/*",
|
||||||
"@eslint/compat": "^1.2.9",
|
"packages/*"
|
||||||
"@formatjs/cli": "^6.7.1",
|
],
|
||||||
"@types/react": "19.2.7",
|
"devDependencies": {
|
||||||
"@types/react-dom": "19.2.3",
|
"@eslint/compat": "^1.2.9",
|
||||||
"@typescript/native-preview": "^7.0.0-dev.20251104.1",
|
"@formatjs/cli": "^6.7.1",
|
||||||
"@yarnpkg/types": "^4.0.1",
|
"@types/react": "19.2.7",
|
||||||
"commander": "^14.0.0",
|
"@types/react-dom": "19.2.3",
|
||||||
"husky": "^9.1.7",
|
"@typescript/native-preview": "^7.0.0-dev.20251104.1",
|
||||||
"jiti": "^1.21.0",
|
"@yarnpkg/types": "^4.0.1",
|
||||||
"lint-staged": "^15.2.2",
|
"commander": "^14.0.0",
|
||||||
"prettier": "^3.6.2",
|
"husky": "^9.1.7",
|
||||||
"turbo": "^2.6.1"
|
"jiti": "^1.21.0",
|
||||||
},
|
"lint-staged": "^15.2.2",
|
||||||
"resolutions": {
|
"prettier": "^3.6.2",
|
||||||
"react": "~19.2.0",
|
"turbo": "^2.6.1"
|
||||||
"react-dom": "~19.2.0",
|
},
|
||||||
"vite": "^7.2.4",
|
"resolutions": {
|
||||||
"import-in-the-middle": "^1.14.2",
|
"react": "~19.2.0",
|
||||||
"@react-aria/overlays": "3.27.3"
|
"react-dom": "~19.2.0",
|
||||||
}
|
"vite": "^7.2.4",
|
||||||
|
"import-in-the-middle": "^1.14.2",
|
||||||
|
"@react-aria/overlays": "3.27.3"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
128
scripts/deploy/deploy.ts
Normal file
128
scripts/deploy/deploy.ts
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
import { execSync } from "node:child_process";
|
||||||
|
import { createInterface } from "node:readline";
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
const ENV_BRANCH_MAP: Record<string, string> = {
|
||||||
|
test: "test",
|
||||||
|
stage: "stage",
|
||||||
|
preprod: "prod",
|
||||||
|
prod: "release",
|
||||||
|
};
|
||||||
|
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const targetEnv = args[0];
|
||||||
|
|
||||||
|
// Validate input
|
||||||
|
if (!targetEnv) {
|
||||||
|
console.error("❌ Error: Please provide an environment.");
|
||||||
|
console.log(
|
||||||
|
`Usage: yarn dlx tsx deploy.ts <${Object.keys(ENV_BRANCH_MAP).join("|")}>`
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetBranch = ENV_BRANCH_MAP[targetEnv];
|
||||||
|
|
||||||
|
if (!targetBranch) {
|
||||||
|
console.error(`❌ Error: Invalid environment '${targetEnv}'.`);
|
||||||
|
console.log(
|
||||||
|
`Available environments: ${Object.keys(ENV_BRANCH_MAP).join(", ")}`
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Git helper
|
||||||
|
const runGit = (
|
||||||
|
command: string,
|
||||||
|
options: { stdio?: "inherit" | "ignore" | "pipe" } = {}
|
||||||
|
) => {
|
||||||
|
return execSync(command, { encoding: "utf-8", ...options }).trim();
|
||||||
|
};
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
try {
|
||||||
|
// Get current branch
|
||||||
|
const currentBranch = runGit("git rev-parse --abbrev-ref HEAD");
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`\n🚀 Preparing to deploy branch '${currentBranch}' to '${targetEnv}' (target branch: '${targetBranch}')`
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check for tagging requirement
|
||||||
|
let tagToCreate: string | null = null;
|
||||||
|
const releaseBranchRegex = /^release-(v\d+\.\d+\.\d+)$/;
|
||||||
|
const releaseBranchMatch = currentBranch.match(releaseBranchRegex);
|
||||||
|
|
||||||
|
if (releaseBranchMatch) {
|
||||||
|
const tagName = releaseBranchMatch[1];
|
||||||
|
try {
|
||||||
|
// Check if tag already exists locally or remote
|
||||||
|
// Checking local first
|
||||||
|
runGit(`git rev-parse ${tagName}`, { stdio: "ignore" });
|
||||||
|
console.log(`ℹ️ Tag '${tagName}' already exists.`);
|
||||||
|
} catch {
|
||||||
|
// Tag doesn't exist
|
||||||
|
tagToCreate = tagName;
|
||||||
|
console.log(`✨ Will create and push tag: '${tagName}'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!releaseBranchMatch && targetEnv === "prod") {
|
||||||
|
console.warn(
|
||||||
|
"⚠️ Warning: Deploying to prod from a non-release branch. No version tag will be created."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirmation prompt
|
||||||
|
const rl = createInterface({
|
||||||
|
input: process.stdin,
|
||||||
|
output: process.stdout,
|
||||||
|
});
|
||||||
|
|
||||||
|
const confirmed = await new Promise<boolean>((resolve) => {
|
||||||
|
rl.question(
|
||||||
|
`\n❓ Are you sure you want to deploy ${currentBranch} to ${targetEnv}? (y/n) `,
|
||||||
|
(answer) => {
|
||||||
|
rl.close();
|
||||||
|
resolve(answer.toLowerCase() === "y");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!confirmed) {
|
||||||
|
console.log("🚫 Deployment aborted.");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("\n🔄 Starting deployment...");
|
||||||
|
|
||||||
|
// 1. Create and push tag if needed
|
||||||
|
if (tagToCreate) {
|
||||||
|
console.log(`🏷️ Creating tag ${tagToCreate}...`);
|
||||||
|
runGit(`git tag ${tagToCreate}`);
|
||||||
|
|
||||||
|
console.log(`⬆️ Pushing tag ${tagToCreate}...`);
|
||||||
|
runGit(`git push origin ${tagToCreate}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Force push to target branch
|
||||||
|
console.log(
|
||||||
|
`🔥 Force pushing '${currentBranch}' to 'origin/${targetBranch}'...`
|
||||||
|
);
|
||||||
|
runGit(
|
||||||
|
`git push origin ${currentBranch}:${targetBranch} --force-with-lease`,
|
||||||
|
{
|
||||||
|
stdio: "inherit",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`\n✅ Deployment to ${targetEnv} completed successfully!`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("\n❌ Deployment failed.");
|
||||||
|
if (error instanceof Error) {
|
||||||
|
console.error(error.message);
|
||||||
|
}
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
Reference in New Issue
Block a user