Skip to content

Commit 024e31c

Browse files
authored
Merge pull request #1450 from ASU/aws-s3-staging
Create staging site for each PR
2 parents 944b925 + 0124850 commit 024e31c

File tree

7 files changed

+146
-36
lines changed

7 files changed

+146
-36
lines changed

Jenkinsfile

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ spec:
2727
command:
2828
- cat
2929
tty: true
30+
- name: aws-cli
31+
image: 'amazon/aws-cli:2.23.2'
32+
imagePullPolicy: Always
33+
command:
34+
- cat
35+
tty: true
3036
imagePullSecrets:
3137
- name: docker-hub-credentials
3238
"""
@@ -37,6 +43,10 @@ spec:
3743
RAW_GH_TOKEN = credentials('github-org-asu-pac')
3844
NPM_TOKEN = credentials('NPM_TOKEN')
3945
NODE_AUTH_TOKEN = credentials('github-org-asu-pac')
46+
AWS_ACCESS_KEY_ID = credentials('AWS_ACCESS_KEY_ID')
47+
AWS_SECRET_ACCESS_KEY = credentials('AWS_SECRET_ACCESS_KEY')
48+
S3_BUCKET = 'unity-uds-staging'
49+
DAYS_TO_SCAN = 14
4050
}
4151
options {
4252
buildDiscarder(logRotator(numToKeepStr: '5', artifactNumToKeepStr: '5'))
@@ -74,6 +84,120 @@ spec:
7484
}
7585
}
7686
}
87+
stage('Deploy to s3') {
88+
when {
89+
changeRequest target: 'dev'
90+
}
91+
steps {
92+
container('node20') {
93+
script {
94+
echo '## Build storybook'
95+
sh 'yarn build-storybook'
96+
}
97+
}
98+
container('aws-cli') {
99+
withEnv(["AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}", "AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}"]) {
100+
script {
101+
echo '## Deploying to S3..'
102+
sh "aws s3 sync ./build/ s3://${S3_BUCKET}/pr-${env.CHANGE_ID}/ --delete"
103+
// comment on the github pr the link to the deployed storybook but only if there is not alreafy a comment
104+
def prNumber = env.CHANGE_ID
105+
def prComments = httpRequest(
106+
url: "https://api.github.com/repos/ASU/asu-unity-stack/issues/${prNumber}/comments",
107+
httpMode: 'GET',
108+
contentType: 'APPLICATION_JSON',
109+
customHeaders: [
110+
[name: 'Authorization', value: "Bearer ${RAW_GH_TOKEN_PSW}"],
111+
[name: 'Accept', value: 'application/vnd.github.v3+json']
112+
]
113+
).content
114+
def prCommentsJson = readJSON text: prComments
115+
def commentExists = false
116+
117+
for (comment in prCommentsJson) {
118+
if (comment.body.contains("Storybook deployed")) {
119+
commentExists = true
120+
break
121+
}
122+
}
123+
if (!commentExists) {
124+
httpRequest(
125+
url: "https://api.github.com/repos/ASU/asu-unity-stack/issues/${prNumber}/comments",
126+
httpMode: 'POST',
127+
contentType: 'APPLICATION_JSON',
128+
customHeaders: [
129+
[name: 'Authorization', value: "Bearer ${RAW_GH_TOKEN_PSW}"],
130+
[name: 'Accept', value: 'application/vnd.github.v3+json']
131+
],
132+
requestBody: """
133+
{
134+
"body": "Storybook deployed at https://${S3_BUCKET}.s3.us-west-2.amazonaws.com/pr-${prNumber}/index.html"
135+
}
136+
"""
137+
)
138+
}
139+
}
140+
}
141+
}
142+
}
143+
}
144+
stage('Cleanup S3 PR Environments') {
145+
when {
146+
branch 'dev'
147+
}
148+
steps {
149+
container('aws-cli') {
150+
script {
151+
// Get recently merged PR numbers from merge commits
152+
def mergedPRs = sh(
153+
script: """
154+
git fetch --all
155+
git log --merges --since="\${DAYS_TO_SCAN} days ago" --grep="Merge pull request #" \
156+
| grep -o '#[0-9]\\+' \
157+
| sed 's/#//' \
158+
| sort -u
159+
""",
160+
returnStdout: true
161+
).trim()
162+
163+
if (!mergedPRs) {
164+
echo "No merged PRs found in the last ${DAYS_TO_SCAN} days. Nothing to clean up."
165+
return
166+
}
167+
168+
def prList = mergedPRs.split('\n').collect { it.trim() }
169+
echo "Recently merged PRs: ${prList}"
170+
171+
withEnv(["AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}", "AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}"]) {
172+
// For each PR, check if files exist and clean up
173+
prList.each { prNumber ->
174+
def prefix = "pr-${prNumber}"
175+
176+
// Check if directory exists
177+
def hasFiles = sh(
178+
script: "aws s3 ls s3://${S3_BUCKET}/${prefix}/",
179+
returnStatus: true
180+
) == 0
181+
182+
if (!hasFiles) {
183+
echo "No files found for PR ${prNumber}, skipping..."
184+
return
185+
}
186+
187+
// List files that would be deleted
188+
def filesToDelete = sh(
189+
script: "aws s3 ls s3://${S3_BUCKET}/${prefix}/ --recursive",
190+
returnStdout: true
191+
).trim()
192+
193+
echo "Cleaning up S3 files for merged PR: ${prNumber}"
194+
sh "aws s3 rm s3://${S3_BUCKET}/${prefix}/ --recursive"
195+
}
196+
}
197+
}
198+
}
199+
}
200+
}
77201
stage('Test') {
78202
steps {
79203
container('playwright') {

packages/component-header-footer/src/footer/components/Innovation/index.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,14 @@
22
import React from "react";
33

44
import { trackGAEvent } from "../../../../../../shared";
5-
import { getCurrentScriptPath } from "../../../../../../shared/utils";
5+
import innovationLogo from "../../assets/images/innovationLogo.png";
66
import { FOOTER_URLS } from "../../core/constants";
77

88
const DEFAULT_GA_EVENT = {
99
type: "internal link",
1010
section: "secondary footer",
1111
};
1212

13-
const currentScriptPath = getCurrentScriptPath();
14-
const innovationLogo = `${currentScriptPath}assets/images/innovationLogo.png`;
15-
1613
const Innovation = () => {
1714
return (
1815
<div

packages/component-header-footer/src/header/components/HeaderMain/Logo/index.js

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
/* eslint-disable import/no-extraneous-dependencies */
22
import React from "react";
33

4-
import {
5-
getCurrentScriptPath,
6-
trackGAEvent,
7-
} from "../../../../../../../shared";
4+
import { trackGAEvent } from "../../../../../../../shared";
5+
import vertLogo from "../../../assets/img/arizona-state-university-logo-vertical.png";
6+
import horizLogo from "../../../assets/img/arizona-state-university-logo.png";
87
import { useAppContext } from "../../../core/context/app-context";
98
import { LogoWrapper } from "./index.styles";
109

11-
const currentScriptPath = getCurrentScriptPath();
12-
13-
const vertLogo = `${currentScriptPath}assets/img/arizona-state-university-logo-vertical.png`;
14-
const horizLogo = `${currentScriptPath}assets/img/arizona-state-university-logo.png`;
15-
1610
const Logo = () => {
1711
const { logo } = useAppContext();
1812

packages/component-header-footer/src/header/components/HeaderMain/Partner/index.js

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
/* eslint-disable import/no-extraneous-dependencies */
22
import React from "react";
33

4-
import {
5-
getCurrentScriptPath,
6-
trackGAEvent,
7-
} from "../../../../../../../shared";
4+
import { trackGAEvent } from "../../../../../../../shared";
85
// @ts-check
6+
import asuVertLogo from "../../../assets/img/arizona-state-university-logo-vertical.png";
7+
import asuHorizLogo from "../../../assets/img/arizona-state-university-logo.png";
8+
import starbucksLogo from "../../../assets/img/asu-starbucks.png";
99
import { useAppContext } from "../../../core/context/app-context";
1010
import { PartnerLogosWrapper } from "./index.styles";
1111

12-
const currentScriptPath = getCurrentScriptPath();
13-
const asuVertLogo = `${currentScriptPath}/assets/img/arizona-state-university-logo-vertical.png`;
14-
const asuHorizLogo = `${currentScriptPath}/assets/img/arizona-state-university-logo.png`;
15-
const starbucksLogo = `${currentScriptPath}/assets/img/asu-starbucks.png`;
16-
1712
const Partner = () => {
1813
const { partnerLogo, logo: asuLogo, breakpoint } = useAppContext();
1914

packages/static-site/src/main.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { RouteObject, RouterProvider, createBrowserRouter } from "react-router-d
77
import Pages, { AppPagesType } from "~/pages/index";
88
import { configRoutes } from "~/routes/config";
99
import { Page } from "vite-plugin-virtual-mpa";
10-
import { getBaseUrl } from "~/utils/baseUrl";
10+
import { getBaseUrl } from "./utils/baseUrl";
1111

1212
/**
1313
* Create duplicate routes for paths ending with "/" and "/index.html"

packages/static-site/src/pages/Home.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ const Home = () => {
4444
title="ASU Header"
4545
description="Guidelines, requirements and best practices for using the ASU
4646
Branded Header in your site."
47-
href={PagePaths.HEADERGUIDE}
47+
href={PagePaths.HEADERGUIDE + "index.html"}
4848
isRoute={true}
4949
linkLabel="View the guide"
5050
/>
5151
<Card
5252
title="Google Tag Manager and data layer"
5353
description="Ensure your site or application has the necessary analytics integrations."
54-
href={PagePaths.DATALAYERGUIDE}
54+
href={PagePaths.DATALAYERGUIDE + "index.html"}
5555
isRoute={true}
5656
linkLabel="GTM and data layer guide"
5757
/>
Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
export const getBaseUrl = () => {
22

3-
const host = window.location.host;
3+
if (typeof window === 'undefined') return '/';
4+
45
const pathname = window.location.pathname;
56

6-
let basename = "/";
7-
if(host.indexOf(".github.io")>-1) {
8-
basename = "/asu-unity-stack";
9-
} else if(pathname.indexOf("/build/") > -1) {
10-
basename = window.location.pathname.replace(/(.*?\/build\/).*/, "$1");
11-
}
7+
const segments = pathname.split('/').filter(Boolean);
8+
return segments.length > 0 ? `/${segments[0]}` : '/';
129

13-
return basename;
14-
}
10+
};
1511

1612
export const getRelativePath = (path: string): string => {
17-
return `${getBaseUrl()}${path}`.replace(/\/\//g, "/");
18-
}
13+
const baseUrl = getBaseUrl();
14+
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
15+
const fullPath = `${baseUrl}${normalizedPath}`;
16+
17+
return fullPath.replace(/\/{2,}/g, '/');
18+
};

0 commit comments

Comments
 (0)