| ... | @@ -948,12 +948,20 @@ jobs: | ... | @@ -948,12 +948,20 @@ jobs: |
| 948 | secrets: | 948 | secrets: |
| 949 | AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }} | 949 | AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }} |
| 950 | | 950 | |
| 951 | deploy_web: | 951 | # Vercel builds the hosted web app while the desktop jobs run. `--skip-domain` |
| 952 | name: Deploy hosted web app | 952 | # keeps the custom domains (the channel and router domains) on the previous |
| 953 | needs: [preflight, relay_public_config, release] | 953 | # deployment until deploy_web aliases them, after the GitHub Release. It does |
| 954 | if: ${{ !failure() && !cancelled() && needs.preflight.result == 'success' && needs.relay_public_config.result == 'success' && needs.release.result == 'success' && needs.preflight.outputs.release_channel != 'preview' }} | 954 | # still move the project's own *.vercel.app production hostname at build time. |
| | 955 | # That hostname sits behind Vercel SSO and is not a user channel, so the |
| | 956 | # npm-before-client order in docs/operations/release.md holds for users. |
| | 957 | build_web: |
| | 958 | name: Build hosted web app |
| | 959 | needs: [preflight, relay_public_config] |
| | 960 | if: ${{ !cancelled() && needs.preflight.result == 'success' && needs.relay_public_config.result == 'success' && needs.preflight.outputs.release_channel != 'preview' }} |
| 955 | runs-on: blacksmith-8vcpu-ubuntu-2404 | 961 | runs-on: blacksmith-8vcpu-ubuntu-2404 |
| 956 | timeout-minutes: 10 | 962 | timeout-minutes: 10 |
| | 963 | outputs: |
| | 964 | deployment_url: ${{ steps.deploy.outputs.deployment_url }} |
| 957 | env: | 965 | env: |
| 958 | T3CODE_CLERK_PUBLISHABLE_KEY: ${{ needs.relay_public_config.outputs.clerk_publishable_key }} | 966 | T3CODE_CLERK_PUBLISHABLE_KEY: ${{ needs.relay_public_config.outputs.clerk_publishable_key }} |
| 959 | T3CODE_CLERK_JWT_TEMPLATE: ${{ needs.relay_public_config.outputs.clerk_jwt_template }} | 967 | T3CODE_CLERK_JWT_TEMPLATE: ${{ needs.relay_public_config.outputs.clerk_jwt_template }} |
| ... | @@ -963,8 +971,6 @@ jobs: | ... | @@ -963,8 +971,6 @@ jobs: |
| 963 | VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} | 971 | VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} |
| 964 | VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} | 972 | VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} |
| 965 | T3CODE_WEB_ROUTER_URL: ${{ vars.T3CODE_WEB_ROUTER_URL }} | 973 | T3CODE_WEB_ROUTER_URL: ${{ vars.T3CODE_WEB_ROUTER_URL }} |
| 966 | T3CODE_WEB_LATEST_DOMAIN: ${{ vars.T3CODE_WEB_LATEST_DOMAIN }} | | |
| 967 | T3CODE_WEB_NIGHTLY_DOMAIN: ${{ vars.T3CODE_WEB_NIGHTLY_DOMAIN }} | | |
| 968 | VERCEL_TEAM_SLUG: ${{ vars.VERCEL_TEAM_SLUG }} | 974 | VERCEL_TEAM_SLUG: ${{ vars.VERCEL_TEAM_SLUG }} |
| 969 | steps: | 975 | steps: |
| 970 | - name: Checkout | 976 | - name: Checkout |
| ... | @@ -1006,7 +1012,8 @@ jobs: | ... | @@ -1006,7 +1012,8 @@ jobs: |
| 1006 | - name: Refresh release lockfile | 1012 | - name: Refresh release lockfile |
| 1007 | run: vp install --lockfile-only --ignore-scripts | 1013 | run: vp install --lockfile-only --ignore-scripts |
| 1008 | | 1014 | |
| 1009 | - name: Deploy and alias channel | 1015 | - id: deploy |
| | 1016 | name: Build staged deployment |
| 1010 | shell: bash | 1017 | shell: bash |
| 1011 | run: | | 1018 | run: | |
| 1012 | set -euo pipefail | 1019 | set -euo pipefail |
| ... | @@ -1017,24 +1024,13 @@ jobs: | ... | @@ -1017,24 +1024,13 @@ jobs: |
| 1017 | fi | 1024 | fi |
| 1018 | | 1025 | |
| 1019 | router_url="${T3CODE_WEB_ROUTER_URL:-https://app.t3.codes}" | 1026 | router_url="${T3CODE_WEB_ROUTER_URL:-https://app.t3.codes}" |
| 1020 | latest_domain="${T3CODE_WEB_LATEST_DOMAIN:-latest.app.t3.codes}" | | |
| 1021 | nightly_domain="${T3CODE_WEB_NIGHTLY_DOMAIN:-nightly.app.t3.codes}" | | |
| 1022 | router_domain="${router_url#http://}" | | |
| 1023 | router_domain="${router_domain#https://}" | | |
| 1024 | router_domain="${router_domain%%/*}" | | |
| 1025 | | | |
| 1026 | if [[ "${{ needs.preflight.outputs.release_channel }}" == "stable" ]]; then | 1027 | if [[ "${{ needs.preflight.outputs.release_channel }}" == "stable" ]]; then |
| 1027 | channel_domain="$latest_domain" | | |
| 1028 | channel_name="latest" | 1028 | channel_name="latest" |
| 1029 | else | 1029 | else |
| 1030 | channel_domain="$nightly_domain" | | |
| 1031 | channel_name="nightly" | 1030 | channel_name="nightly" |
| 1032 | fi | 1031 | fi |
| 1033 | | 1032 | |
| 1034 | vercel_scope="${VERCEL_TEAM_SLUG:-$VERCEL_ORG_ID}" | 1033 | echo "Building hosted web app for $channel_name channel." |
| 1035 | vercel_scope_args=(--scope "$vercel_scope") | | |
| 1036 | | | |
| 1037 | echo "Deploying hosted web app for $channel_name channel." | | |
| 1038 | deployment_url="$( | 1034 | deployment_url="$( |
| 1039 | vp dlx vercel@53.1.1 deploy \ | 1035 | vp dlx vercel@53.1.1 deploy \ |
| 1040 | --archive=tgz \ | 1036 | --archive=tgz \ |
| ... | @@ -1042,7 +1038,7 @@ jobs: | ... | @@ -1042,7 +1038,7 @@ jobs: |
| 1042 | --skip-domain \ | 1038 | --skip-domain \ |
| 1043 | --yes \ | 1039 | --yes \ |
| 1044 | --token "$VERCEL_TOKEN" \ | 1040 | --token "$VERCEL_TOKEN" \ |
| 1045 | "${vercel_scope_args[@]}" \ | 1041 | --scope "${VERCEL_TEAM_SLUG:-$VERCEL_ORG_ID}" \ |
| 1046 | --build-env "APP_VERSION=${{ needs.preflight.outputs.version }}" \ | 1042 | --build-env "APP_VERSION=${{ needs.preflight.outputs.version }}" \ |
| 1047 | --build-env "T3CODE_CLERK_PUBLISHABLE_KEY=${T3CODE_CLERK_PUBLISHABLE_KEY:-}" \ | 1043 | --build-env "T3CODE_CLERK_PUBLISHABLE_KEY=${T3CODE_CLERK_PUBLISHABLE_KEY:-}" \ |
| 1048 | --build-env "T3CODE_CLERK_JWT_TEMPLATE=${T3CODE_CLERK_JWT_TEMPLATE:-}" \ | 1044 | --build-env "T3CODE_CLERK_JWT_TEMPLATE=${T3CODE_CLERK_JWT_TEMPLATE:-}" \ |
| ... | @@ -1054,25 +1050,92 @@ jobs: | ... | @@ -1054,25 +1050,92 @@ jobs: |
| 1054 | --build-env "VITE_HOSTED_APP_URL=$router_url" \ | 1050 | --build-env "VITE_HOSTED_APP_URL=$router_url" \ |
| 1055 | --build-env "VITE_HOSTED_APP_CHANNEL=$channel_name" | 1051 | --build-env "VITE_HOSTED_APP_CHANNEL=$channel_name" |
| 1056 | )" | 1052 | )" |
| | 1053 | echo "Staged $deployment_url." |
| | 1054 | echo "deployment_url=$deployment_url" >> "$GITHUB_OUTPUT" |
| 1057 | | 1055 | |
| 1058 | echo "Aliasing $deployment_url to $channel_domain." | 1056 | deploy_web: |
| 1059 | vp dlx vercel@53.1.1 alias set "$deployment_url" "$channel_domain" \ | 1057 | name: Deploy hosted web app |
| | 1058 | needs: [preflight, build_web, release] |
| | 1059 | if: ${{ !failure() && !cancelled() && needs.preflight.result == 'success' && needs.build_web.result == 'success' && needs.release.result == 'success' && needs.preflight.outputs.release_channel != 'preview' }} |
| | 1060 | runs-on: blacksmith-2vcpu-ubuntu-2404 |
| | 1061 | timeout-minutes: 10 |
| | 1062 | env: |
| | 1063 | DEPLOYMENT_URL: ${{ needs.build_web.outputs.deployment_url }} |
| | 1064 | VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} |
| | 1065 | VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} |
| | 1066 | VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} |
| | 1067 | T3CODE_WEB_ROUTER_URL: ${{ vars.T3CODE_WEB_ROUTER_URL }} |
| | 1068 | T3CODE_WEB_LATEST_DOMAIN: ${{ vars.T3CODE_WEB_LATEST_DOMAIN }} |
| | 1069 | T3CODE_WEB_NIGHTLY_DOMAIN: ${{ vars.T3CODE_WEB_NIGHTLY_DOMAIN }} |
| | 1070 | VERCEL_TEAM_SLUG: ${{ vars.VERCEL_TEAM_SLUG }} |
| | 1071 | steps: |
| | 1072 | - name: Checkout |
| | 1073 | uses: actions/checkout@v6 |
| | 1074 | with: |
| | 1075 | ref: ${{ needs.preflight.outputs.ref }} |
| | 1076 | sparse-checkout: | |
| | 1077 | /* |
| | 1078 | !/.repos/ |
| | 1079 | sparse-checkout-cone-mode: false |
| | 1080 | |
| | 1081 | - name: Setup Vite+ |
| | 1082 | uses: voidzero-dev/setup-vp@v1 |
| | 1083 | with: |
| | 1084 | node-version-file: package.json |
| | 1085 | cache: false |
| | 1086 | run-install: false |
| | 1087 | |
| | 1088 | - name: Alias channel |
| | 1089 | shell: bash |
| | 1090 | run: | |
| | 1091 | set -euo pipefail |
| | 1092 | |
| | 1093 | if [[ -z "$DEPLOYMENT_URL" ]]; then |
| | 1094 | echo "Build hosted web app did not report a deployment URL." >&2 |
| | 1095 | exit 1 |
| | 1096 | fi |
| | 1097 | |
| | 1098 | router_url="${T3CODE_WEB_ROUTER_URL:-https://app.t3.codes}" |
| | 1099 | latest_domain="${T3CODE_WEB_LATEST_DOMAIN:-latest.app.t3.codes}" |
| | 1100 | nightly_domain="${T3CODE_WEB_NIGHTLY_DOMAIN:-nightly.app.t3.codes}" |
| | 1101 | router_domain="${router_url#http://}" |
| | 1102 | router_domain="${router_domain#https://}" |
| | 1103 | router_domain="${router_domain%%/*}" |
| | 1104 | |
| | 1105 | if [[ "${{ needs.preflight.outputs.release_channel }}" == "stable" ]]; then |
| | 1106 | channel_domain="$latest_domain" |
| | 1107 | channel_name="latest" |
| | 1108 | else |
| | 1109 | channel_domain="$nightly_domain" |
| | 1110 | channel_name="nightly" |
| | 1111 | fi |
| | 1112 | |
| | 1113 | vercel_scope_args=(--scope "${VERCEL_TEAM_SLUG:-$VERCEL_ORG_ID}") |
| | 1114 | |
| | 1115 | echo "Aliasing $DEPLOYMENT_URL to $channel_domain." |
| | 1116 | vp dlx vercel@53.1.1 alias set "$DEPLOYMENT_URL" "$channel_domain" \ |
| 1060 | --token "$VERCEL_TOKEN" \ | 1117 | --token "$VERCEL_TOKEN" \ |
| 1061 | "${vercel_scope_args[@]}" | 1118 | "${vercel_scope_args[@]}" |
| 1062 | | 1119 | |
| 1063 | if [[ "$channel_name" == "latest" && -n "$router_domain" && "$router_domain" != "$channel_domain" ]]; then | 1120 | if [[ "$channel_name" == "latest" && -n "$router_domain" && "$router_domain" != "$channel_domain" ]]; then |
| 1064 | echo "Aliasing $deployment_url to router domain $router_domain." | 1121 | echo "Aliasing $DEPLOYMENT_URL to router domain $router_domain." |
| 1065 | vp dlx vercel@53.1.1 alias set "$deployment_url" "$router_domain" \ | 1122 | vp dlx vercel@53.1.1 alias set "$DEPLOYMENT_URL" "$router_domain" \ |
| 1066 | --token "$VERCEL_TOKEN" \ | 1123 | --token "$VERCEL_TOKEN" \ |
| 1067 | "${vercel_scope_args[@]}" | 1124 | "${vercel_scope_args[@]}" |
| 1068 | fi | 1125 | fi |
| 1069 | | 1126 | |
| 1070 | deploy_marketing: | 1127 | # Same split as the web app: build a production deployment early, then |
| 1071 | name: Deploy marketing site | 1128 | # promote it to t3.codes once the release it links to exists. As above, the |
| 1072 | needs: [preflight, release] | 1129 | # project's own *.vercel.app hostname moves at build time. |
| 1073 | if: ${{ !failure() && !cancelled() && needs.preflight.result == 'success' && needs.release.result == 'success' && needs.preflight.outputs.release_channel == 'nightly' }} | 1130 | build_marketing: |
| | 1131 | name: Build marketing site |
| | 1132 | needs: [preflight] |
| | 1133 | if: ${{ !cancelled() && needs.preflight.result == 'success' && needs.preflight.outputs.release_channel == 'nightly' }} |
| 1074 | runs-on: blacksmith-8vcpu-ubuntu-2404 | 1134 | runs-on: blacksmith-8vcpu-ubuntu-2404 |
| 1075 | timeout-minutes: 10 | 1135 | timeout-minutes: 10 |
| | 1136 | outputs: |
| | 1137 | deployment_url: ${{ steps.deploy.outputs.deployment_url }} |
| | 1138 | project_id: ${{ steps.deploy.outputs.project_id }} |
| 1076 | env: | 1139 | env: |
| 1077 | VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} | 1140 | VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} |
| 1078 | VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} | 1141 | VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} |
| ... | @@ -1096,7 +1159,8 @@ jobs: | ... | @@ -1096,7 +1159,8 @@ jobs: |
| 1096 | args: | 1159 | args: |
| 1097 | - --filter=@t3tools/marketing... | 1160 | - --filter=@t3tools/marketing... |
| 1098 | | 1161 | |
| 1099 | - name: Deploy marketing site to Vercel | 1162 | - id: deploy |
| | 1163 | name: Build staged deployment |
| 1100 | shell: bash | 1164 | shell: bash |
| 1101 | run: | | 1165 | run: | |
| 1102 | set -euo pipefail | 1166 | set -euo pipefail |
| ... | @@ -1114,9 +1178,60 @@ jobs: | ... | @@ -1114,9 +1178,60 @@ jobs: |
| 1114 | )" | 1178 | )" |
| 1115 | export VERCEL_PROJECT_ID | 1179 | export VERCEL_PROJECT_ID |
| 1116 | | 1180 | |
| 1117 | vp dlx vercel@53.1.1 deploy \ | 1181 | deployment_url="$( |
| 1118 | --archive=tgz \ | 1182 | vp dlx vercel@53.1.1 deploy \ |
| 1119 | --prod \ | 1183 | --archive=tgz \ |
| | 1184 | --prod \ |
| | 1185 | --skip-domain \ |
| | 1186 | --yes \ |
| | 1187 | --token "$VERCEL_TOKEN" \ |
| | 1188 | --scope "${VERCEL_TEAM_SLUG:-$VERCEL_ORG_ID}" |
| | 1189 | )" |
| | 1190 | echo "Staged $deployment_url." |
| | 1191 | echo "deployment_url=$deployment_url" >> "$GITHUB_OUTPUT" |
| | 1192 | echo "project_id=$VERCEL_PROJECT_ID" >> "$GITHUB_OUTPUT" |
| | 1193 | |
| | 1194 | deploy_marketing: |
| | 1195 | name: Deploy marketing site |
| | 1196 | needs: [preflight, build_marketing, release] |
| | 1197 | if: ${{ !failure() && !cancelled() && needs.preflight.result == 'success' && needs.build_marketing.result == 'success' && needs.release.result == 'success' && needs.preflight.outputs.release_channel == 'nightly' }} |
| | 1198 | runs-on: blacksmith-2vcpu-ubuntu-2404 |
| | 1199 | timeout-minutes: 10 |
| | 1200 | env: |
| | 1201 | DEPLOYMENT_URL: ${{ needs.build_marketing.outputs.deployment_url }} |
| | 1202 | VERCEL_PROJECT_ID: ${{ needs.build_marketing.outputs.project_id }} |
| | 1203 | VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} |
| | 1204 | VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} |
| | 1205 | VERCEL_TEAM_SLUG: ${{ vars.VERCEL_TEAM_SLUG }} |
| | 1206 | steps: |
| | 1207 | - name: Checkout |
| | 1208 | uses: actions/checkout@v6 |
| | 1209 | with: |
| | 1210 | ref: ${{ needs.preflight.outputs.ref }} |
| | 1211 | sparse-checkout: | |
| | 1212 | /* |
| | 1213 | !/.repos/ |
| | 1214 | sparse-checkout-cone-mode: false |
| | 1215 | |
| | 1216 | - name: Setup Vite+ |
| | 1217 | uses: voidzero-dev/setup-vp@v1 |
| | 1218 | with: |
| | 1219 | node-version-file: package.json |
| | 1220 | cache: false |
| | 1221 | run-install: false |
| | 1222 | |
| | 1223 | - name: Promote marketing site |
| | 1224 | shell: bash |
| | 1225 | run: | |
| | 1226 | set -euo pipefail |
| | 1227 | |
| | 1228 | if [[ -z "$DEPLOYMENT_URL" ]]; then |
| | 1229 | echo "Build marketing site did not report a deployment URL." >&2 |
| | 1230 | exit 1 |
| | 1231 | fi |
| | 1232 | |
| | 1233 | echo "Promoting $DEPLOYMENT_URL." |
| | 1234 | vp dlx vercel@53.1.1 promote "$DEPLOYMENT_URL" \ |
| 1120 | --yes \ | 1235 | --yes \ |
| 1121 | --token "$VERCEL_TOKEN" \ | 1236 | --token "$VERCEL_TOKEN" \ |
| 1122 | --scope "${VERCEL_TEAM_SLUG:-$VERCEL_ORG_ID}" | 1237 | --scope "${VERCEL_TEAM_SLUG:-$VERCEL_ORG_ID}" |