Skip to content
This repository has been archived by the owner on Mar 10, 2024. It is now read-only.

Commit

Permalink
Use title and ci updates (#63)
Browse files Browse the repository at this point in the history
* copy workflows from dpgraham-server for building and pushing docker images

* quick add error handling in DpgMarkdownArticle, use new backend URL

* useTitle custom hook

* utilize useTitle hook in features
  • Loading branch information
dpgraham4401 authored Jul 24, 2023
1 parent 5ff9ff5 commit 82b82d9
Show file tree
Hide file tree
Showing 14 changed files with 222 additions and 19 deletions.
31 changes: 19 additions & 12 deletions .github/workflows/build-gcp-image.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,34 @@
name: Docker build and push to Artifact Registry

on:
push:
branches:
- main
release:
types: [ published ]
workflow_call:
inputs:
environment:
description: 'The environment to deploy to'
required: true
type: string
default: 'production'
outputs:
version:
description: 'The version of the image that was built'
value: ${{ jobs.build_push.outputs.version }}

env:
PROJECT_ID: dpgraham
GOOGLE_REGISTRY_LOCATION: us-east1
REPOSITORY: dpgraham-com
IMAGE_NAME: dpgraham-client
PROJECT_ID: ${{ vars.PROJECT_ID }}
REPOSITORY: ${{ vars.REPOSITORY }}
IMAGE_NAME: ${{ vars.IMAGE_NAME }}
GOOGLE_REGISTRY_LOCATION: ${{ vars.GOOGLE_REGISTRY_LOCATION }}

jobs:
build-push:
build_push:
name: Build Image for GCP
environment: dev
environment: ${{ inputs.environment }}
permissions:
contents: 'read'
id-token: 'write'
runs-on: ubuntu-latest
outputs:
version: ${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}

steps:
- name: Checkout
Expand All @@ -42,7 +50,6 @@ jobs:
with:
images: ${{ env.GOOGLE_REGISTRY_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=ref,event=tag
type=semver,pattern={{version}}
Expand Down
4 changes: 1 addition & 3 deletions .github/workflows/build-ghcr-image.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ name: 'Build Image for GitHub Container Registry'
# - It will name the image the same as the repository name

on:
push:
tags:
- '*'
workflow_call:

jobs:
build_docker_image:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/build-push-gcp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ on:
branches:
- main
release:
types: [published]
types: [ published ]

env:
PROJECT_ID: dpgraham
Expand All @@ -25,7 +25,7 @@ env:

jobs:
build-push:
environment: staging
environment: production
permissions:
contents: 'read'
id-token: 'write'
Expand Down
55 changes: 55 additions & 0 deletions .github/workflows/cloud-run-deploy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Reusable Workflow to deploy a new revision to Cloud Run

name: Deploy to Cloud Run

on:
workflow_call:
inputs:
environment:
description: 'The environment to deploy to'
required: true
type: string
default: 'production'
version:
description: 'The version of the image to deploy'
required: true
type: string
default: 'latest'
service:
description: 'The name of the Cloud Run service to deploy to'
required: true
type: string
default: 'dpgraham-client'

env:
PROJECT_ID: ${{ vars.PROJECT_ID }}
REPOSITORY: ${{ vars.REPOSITORY }}
IMAGE_NAME: ${{ vars.IMAGE_NAME }}
GOOGLE_REGISTRY_LOCATION: ${{ vars.GOOGLE_REGISTRY_LOCATION }}

jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
permissions:
contents: 'read'
id-token: 'write'

steps:
- uses: 'actions/checkout@v3'


- name: Authenticate Google Cloud
uses: google-github-actions/auth@v1
id: auth
with:
credentials_json: ${{ secrets.GOOGLE_CREDENTIALS }}
token_format: 'access_token'

- name: Deploy to Cloud Run
id: deploy
uses: 'google-github-actions/deploy-cloudrun@v1'
with:
service: ${{ inputs.service }}
image: ${{ env.GOOGLE_REGISTRY_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ inputs.version }}
region: ${{ env.GOOGLE_REGISTRY_LOCATION }}
30 changes: 30 additions & 0 deletions .github/workflows/on-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This Workflow deploys a Docker image to Google Cloud Run

name: On Release

on:
release:
types: [ published ]

jobs:
build_gcp_image:
name: Build Image for GCP
uses: ./.github/workflows/build-gcp-image.yaml
with:
environment: production
secrets: inherit

deploy_to_cloud_run:
name: Deploy to Cloud Run
uses: ./.github/workflows/cloud-run-deploy.yaml
needs: build_gcp_image
with:
environment: production
version: ${{ needs.build_gcp_image.outputs.version }}
service: dpgraham-server
secrets: inherit

build_ghcr_image:
name: Build Image for GHCR
uses: ./.github/workflows/build-ghcr-image.yaml
secrets: inherit
2 changes: 1 addition & 1 deletion src/components/article/ArticlesOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import React from "react";
import { useQuery } from "services";

export function ArticlesOverview() {
const [articles, loading, error] = useQuery<Article[]>("blog");
const [articles, loading, error] = useQuery<Article[]>("article");

if (error) {
return <DpgPageError statusCode={404} message={error.message} />;
Expand Down
7 changes: 6 additions & 1 deletion src/components/article/MarkdownArticle.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { faCircleNotch } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Card, CardContent, Container } from "@mui/material";
import { DpgPageError } from "components/DpgError";
import { DpgMarkdown } from "components/DpgMarkdown";
import { Article } from "features/Articles";
import React from "react";
Expand All @@ -9,7 +10,11 @@ import { useQuery } from "services";

export function MarkdownArticle() {
const { id } = useParams();
const [article, loading, error] = useQuery<Article>(`blog/${id}`);
const [article, loading, error] = useQuery<Article>(`article/${id}`);

if (error) {
return <DpgPageError statusCode={404} message={error.message} />;
}

return (
<>
Expand Down
3 changes: 3 additions & 0 deletions src/components/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { useTitle } from "components/hooks/useTitle";

export { useTitle };
56 changes: 56 additions & 0 deletions src/components/hooks/useTitle.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { cleanup, fireEvent, render, screen } from "@testing-library/react";
import React from "react";
import { useTitle } from "components/hooks";

const originalPageTitle = "originalPageTitle";
const newPageTitle = "newPageTitle";

interface TestCompProps {
prevailOnUnmount?: boolean;
excludeAppend?: boolean;
}

function TestComponent({ prevailOnUnmount, excludeAppend }: TestCompProps) {
const [pageTitle, setPageTitle] = useTitle(
originalPageTitle,
prevailOnUnmount,
excludeAppend
);
return (
<>
<p>Hello!</p>
<button onClick={() => setPageTitle(newPageTitle)}>Change Title</button>
<p>{pageTitle ? pageTitle : "undefined"}</p>
</>
);
}

afterEach(() => {
cleanup();
});

describe("useTitle", () => {
it('sets the initial page title, plus " | David Paul Graham"', () => {
render(<TestComponent />);
expect(document.title).toContain(originalPageTitle);
});
it("changes the page title", () => {
render(<TestComponent />);
fireEvent.click(screen.getByText(/Change Title/i));
expect(document.title).toContain(newPageTitle);
});
it("The state is updated when the title is changed", () => {
render(<TestComponent />);
expect(screen.getByText(/undefined/i)).toBeInTheDocument();
fireEvent.click(screen.getByText(/Change Title/i));
expect(screen.getByText(newPageTitle)).toBeInTheDocument();
});
it("appends Global site title to each page title by default", () => {
render(<TestComponent />);
expect(document.title).toContain("David Paul Graham");
});
it("does not appends Global site title if specified", () => {
render(<TestComponent excludeAppend={true} />);
expect(document.title).not.toContain("David Paul Graham");
});
});
41 changes: 41 additions & 0 deletions src/components/hooks/useTitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useEffect, useRef, useState } from "react";

/**
* Hook to set document title
*
* @description Can be used to page the title dynamically or just once per page.
* By default, it reset the title to the previous title when the component using this hook unmounts
* @param title {string}
* @param resetOnUnmount {boolean}
* @param excludeSuffix {boolean}
*/
export function useTitle(
title: string,
resetOnUnmount = false,
excludeSuffix = false
) {
const defaultTitle = useRef(document.title);
const [dynTitle, setDynTitle] = useState<string | undefined>(undefined);

useEffect(() => {
document.title = `${title}${excludeSuffix ? "" : " | David Paul Graham"}`;
}, [excludeSuffix, title]);

useEffect(() => {
if (typeof dynTitle === "string")
document.title = `${dynTitle}${
excludeSuffix ? "" : " | David Paul Graham"
}`;
}, [dynTitle, excludeSuffix]);

useEffect(
// run on unmount
() => () => {
if (!resetOnUnmount) {
document.title = defaultTitle.current;
}
},
[resetOnUnmount]
);
return [dynTitle, setDynTitle] as const;
}
2 changes: 2 additions & 0 deletions src/features/AboutMe/AboutMe.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Box } from "@mui/material";
import { useTitle } from "components/hooks";
import React from "react";

export function AboutMe() {
useTitle("About Me");
return (
<Box padding={4}>
<p>coming soon</p>
Expand Down
2 changes: 2 additions & 0 deletions src/features/Articles/Articles.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Box } from "@mui/material";
import { ArticlesOverview, MarkdownArticle } from "components/article";
import { useTitle } from "components/hooks";
import React from "react";
import { Route, Routes } from "react-router-dom";

Expand All @@ -12,6 +13,7 @@ export interface Article {
}

export function Articles() {
useTitle("Articles");
return (
<Box padding={4}>
<Routes>
Expand Down
2 changes: 2 additions & 0 deletions src/features/Home/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Box, Grid, IconButton, Typography } from "@mui/material";
import { useTitle } from "components/hooks";
import React from "react";

/**
* Landing Page
* @constructor
*/
export function Home() {
useTitle("Home");
return (
<>
<Box className={"aniGradient"} p={2}>
Expand Down
2 changes: 2 additions & 0 deletions src/features/Resume/Resume.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { CloudChallengeResume } from "components/CloudChallengeResume";
import { useTitle } from "components/hooks";
import React from "react";

/**
Expand All @@ -7,5 +8,6 @@ import React from "react";
*/
export function Resume() {
// ToDo - Add a way to download PDF resume
useTitle("Resume");
return <CloudChallengeResume />;
}

0 comments on commit 82b82d9

Please sign in to comment.