Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 61 additions & 9 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,49 +5,101 @@ on:
- main
paths-ignore:
- '**.md'

concurrency:
group: andymeier-deploy
cancel-in-progress: false

jobs:
update:
name: Update
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
id-token: write
pull-requests: write
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: 24.x
- name: Setup gcloud
uses: google-github-actions/setup-gcloud@v2
uses: google-github-actions/setup-gcloud@v3
with:
install_components: gke-gcloud-auth-plugin
- name: Install Packages
working-directory: ./pulumi
run: npm install
run: npm ci
- name: TypeScript Check
working-directory: ./pulumi
run: npm run check
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
with:
version: latest
- name: Expose GitHub Actions cache env
uses: actions/github-script@v7
uses: actions/github-script@v9
with:
script: |
core.exportVariable('ACTIONS_CACHE_URL', process.env['ACTIONS_CACHE_URL'])
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env['ACTIONS_RUNTIME_TOKEN'])
- name: Authenticate Pulumi
uses: pulumi/auth-actions@v1
uses: pulumi/auth-actions@v2
with:
organization: meiermade
requested-token-type: urn:pulumi:token-type:access_token:personal
scope: user:meiermade
- name: Update
uses: pulumi/actions@v6
uses: pulumi/actions@v7
with:
work-dir: ./pulumi
command: up
stack-name: prod

e2e:
name: E2E
needs: update
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
steps:
- uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@v7
with:
node-version: 24.x
cache: npm
cache-dependency-path: e2e/package-lock.json
- name: Install E2E packages
working-directory: ./e2e
run: npm ci
- name: Install Firefox
working-directory: ./e2e
run: npx playwright install --with-deps firefox
- name: Wait for deployed site
run: |
for attempt in $(seq 1 60); do
if curl --fail --silent --show-error https://andymeier.dev/health >/dev/null; then
exit 0
fi
sleep 5
done
echo "Andy Meier site did not become ready." >&2
exit 1
- name: Run E2E against deployed site
working-directory: ./e2e
run: npx playwright test --project=firefox --retries=0
env:
E2E_START_LOCAL: '0'
SITE_E2E_BASE_URL: https://andymeier.dev
- name: Upload E2E diagnostics
if: failure()
uses: actions/upload-artifact@v7
with:
name: andymeier-deploy-e2e
path: |
e2e/playwright-report
e2e/test-results
if-no-files-found: ignore
57 changes: 47 additions & 10 deletions .github/workflows/preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ jobs:
test:
name: Test
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Setup .NET
uses: actions/setup-dotnet@v4
uses: actions/setup-dotnet@v6
with:
dotnet-version: 10.x
- name: Restore Tools & Dependencies
Expand All @@ -23,48 +26,82 @@ jobs:
- name: Run Tests
working-directory: ./app
run: dotnet run --project src/Tests/Tests.fsproj
- name: Setup Node
uses: actions/setup-node@v7
with:
node-version: 24.x
cache: npm
cache-dependency-path: e2e/package-lock.json
- name: Install E2E packages
working-directory: ./e2e
run: npm ci
- name: Install Firefox
working-directory: ./e2e
run: npx playwright install --with-deps firefox
- name: Install Tailwind CSS
run: |
curl --fail --location --silent --show-error \
https://github.com/tailwindlabs/tailwindcss/releases/download/v4.2.2/tailwindcss-linux-x64 \
--output /tmp/tailwindcss
echo '4ab84f2b496c402d3ec4fd25e0e5559fe1184d886dadae8fb4438344ec044c22 /tmp/tailwindcss' | sha256sum --check
sudo install /tmp/tailwindcss /usr/local/bin/tailwindcss
- name: Run local E2E
working-directory: ./e2e
run: npx playwright test --project=firefox
- name: Upload E2E diagnostics
if: failure()
uses: actions/upload-artifact@v7
with:
name: andymeier-preview-e2e
path: |
e2e/playwright-report
e2e/test-results
/tmp/andymeier-e2e
if-no-files-found: ignore
preview:
name: Preview
if: github.event.pull_request.head.repo.full_name == github.repository
needs: test
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
id-token: write
pull-requests: write
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: 24.x
- name: Setup gcloud
uses: google-github-actions/setup-gcloud@v2
uses: google-github-actions/setup-gcloud@v3
with:
install_components: gke-gcloud-auth-plugin
- name: Install Packages
working-directory: ./pulumi
run: npm install
run: npm ci
- name: TypeScript Check
working-directory: ./pulumi
run: npm run check
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
with:
version: latest
- name: Expose GitHub Actions cache env
uses: actions/github-script@v7
uses: actions/github-script@v9
with:
script: |
core.exportVariable('ACTIONS_CACHE_URL', process.env['ACTIONS_CACHE_URL'])
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env['ACTIONS_RUNTIME_TOKEN'])
- name: Authenticate Pulumi
uses: pulumi/auth-actions@v1
uses: pulumi/auth-actions@v2
with:
organization: meiermade
requested-token-type: urn:pulumi:token-type:access_token:personal
scope: user:meiermade
- name: Preview
uses: pulumi/actions@v6
uses: pulumi/actions@v7
with:
work-dir: ./pulumi
command: preview
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
node_modules
.pi/
app/.data/
e2e/playwright-report/
e2e/test-results/
5 changes: 3 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
Before creating a PR, always run:

1. `cd app && ./fake.sh Test` — all tests must pass
2. `cd pulumi && pulumi preview` — must show expected changes with no errors
2. `cd pulumi && npm ci && npm run check` — Pulumi TypeScript must compile
3. Maintainers with access to the `andymeier/prod` ESC environment run `pulumi preview` when infrastructure changes

CI runs `pulumi up` on merge to main, so do **not** run `pulumi up` manually.
External contributors are not expected to have Pulumi credentials. CI runs `pulumi up` on merge to main, so do **not** run `pulumi up` manually.
2 changes: 0 additions & 2 deletions CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
* @andymeierdev
* @benjimeierdev
* @minniemeierdev
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Personal website for Andy Meier built with F#, Giraffe, Datastar, and Tailwind C
- `src/App/` - Main application (Giraffe + Datastar)
- `src/Build/` - FAKE build script
- `src/Tests/` - Expecto tests
- `pulumi/` - Infrastructure as code (AWS ECR, Cloudflare, Kubernetes)
- `pulumi/` - Infrastructure as code (GCP Artifact Registry, Cloudflare, Kubernetes)

## Development

Expand All @@ -21,6 +21,8 @@ dotnet paket restore
./fake.sh Watch
```

`Watch` starts a local MockNotion service with fictional articles, so normal local development does not require Notion credentials or a Pulumi ESC environment.

## Testing

```bash
Expand Down
27 changes: 27 additions & 0 deletions THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Third-party notices

This repository includes browser assets from the following projects.

## Datastar 1.0.0-RC.6

Source: https://github.com/starfederation/datastar

Copyright © Star Federation

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

## PrismJS 1.29.0

Source: https://github.com/PrismJS/prism

Copyright (c) 2012 Lea Verou

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 changes: 7 additions & 1 deletion app/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ WORKDIR /app

# install tailwindcss v4 CLI (match builder platform)
RUN ARCH=$(uname -m | sed 's/aarch64/arm64/' | sed 's/x86_64/x64/') \
&& curl -fsSLo /usr/local/bin/tailwindcss "https://github.com/tailwindlabs/tailwindcss/releases/download/v4.2.1/tailwindcss-linux-${ARCH}" \
&& case "$ARCH" in \
arm64) SHA256=ad627e77b496cccada4a6e26eafff698ef0829081e575a4baf3af8524bb00747 ;; \
x64) SHA256=4ab84f2b496c402d3ec4fd25e0e5559fe1184d886dadae8fb4438344ec044c22 ;; \
*) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;; \
esac \
&& curl -fsSLo /usr/local/bin/tailwindcss "https://github.com/tailwindlabs/tailwindcss/releases/download/v4.2.2/tailwindcss-linux-${ARCH}" \
&& echo "$SHA256 /usr/local/bin/tailwindcss" | sha256sum --check \
&& chmod +x /usr/local/bin/tailwindcss

# restore tools
Expand Down
1 change: 1 addition & 0 deletions app/andrewmeier.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<Project Path="src/App/App.fsproj" />
<Project Path="src/Build/Build.fsproj" />
<Project Path="src/Domain/Domain.fsproj" />
<Project Path="src/MockNotion/MockNotion.fsproj" />
<Project Path="src/Tests/Tests.fsproj" />
</Folder>
</Solution>
11 changes: 10 additions & 1 deletion app/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
services:
mock-notion:
build:
context: .
dockerfile: src/MockNotion/Dockerfile
ports:
- "127.0.0.1:5015:5015"
environment:
MOCK_NOTION_URL: http://0.0.0.0:5015

seq:
image: datalust/seq:2024.3
environment:
ACCEPT_EULA: Y
ports:
- "5341:80"
- "127.0.0.1:5341:80"
Loading
Loading