Skip to content

Commit 43eeaf6

Browse files
feat: deploy on v* tag, update terraform to support email routing and router for nightly site/docs
1 parent 04b697f commit 43eeaf6

5 files changed

Lines changed: 167 additions & 34 deletions

File tree

.github/workflows/deploy.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Deploy Landing Site
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
tags:
8+
- "v*"
9+
10+
jobs:
11+
deploy-landing:
12+
runs-on: ubuntu-latest
13+
permissions:
14+
contents: read
15+
deployments: write
16+
name: Deploy Landing Site
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
- name: Setup Node.js
21+
uses: actions/setup-node@v4
22+
with:
23+
node-version: '20'
24+
25+
- name: Install pnpm
26+
uses: pnpm/action-setup@v2
27+
with:
28+
version: 8
29+
30+
- name: Install dependencies
31+
working-directory: site
32+
run: pnpm install
33+
34+
- name: Build
35+
working-directory: site
36+
run: pnpm run build
37+
38+
- name: Deploy to Cloudflare Pages
39+
uses: cloudflare/pages-action@v1
40+
with:
41+
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
42+
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
43+
projectName: pywire-landing
44+
directory: site/dist
45+
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
46+
branch: ${{ github.ref_name == 'main' && 'nightly' || 'main' }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# Terraform state files (contain secrets in plain text!)
66
terraform.tfstate
77
terraform.tfstate.backup
8+
terraform.tfstate.*.backup
89
.terraform/
910
.terraform.lock.hcl
1011

infra/main.tf

Lines changed: 88 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,36 +11,14 @@ provider "cloudflare" {
1111
api_token = var.cloudflare_api_token
1212
}
1313

14-
variable "account_id" {
15-
type = string
16-
}
17-
18-
variable "cloudflare_api_token" {
19-
type = string
20-
sensitive = true
21-
}
22-
23-
# Add this block!
24-
variable "zone_id" {
25-
type = string
26-
}
27-
2814
# --- 1. The Documentation Site (Project A) ---
2915
# Connects to the 'pywire/pywire' repo
3016
resource "cloudflare_pages_project" "docs" {
3117
account_id = var.account_id
3218
name = "pywire-docs"
3319
production_branch = "main"
3420

35-
source = {
36-
type = "github"
37-
config = {
38-
owner = "pywire"
39-
repo_name = "pywire"
40-
production_deployment_enabled = true
41-
pr_comments_enabled = true
42-
}
43-
}
21+
4422

4523
build_config = {
4624
root_dir = "docs"
@@ -54,15 +32,6 @@ resource "cloudflare_pages_project" "landing" {
5432
name = "pywire-landing"
5533
production_branch = "main"
5634

57-
source = {
58-
type = "github"
59-
config = {
60-
owner = "pywire"
61-
repo_name = "pywire.dev"
62-
production_deployment_enabled = true
63-
}
64-
}
65-
6635
build_config = {
6736
root_dir = "site"
6837
build_command = "pnpm run build"
@@ -79,9 +48,96 @@ resource "cloudflare_workers_script" "router" {
7948
main_module = "index.js"
8049
}
8150

51+
# --- Nightly Environment ---
52+
# 1. DNS Record
53+
resource "cloudflare_dns_record" "nightly" {
54+
zone_id = var.zone_id
55+
name = "nightly"
56+
content = cloudflare_pages_project.landing.subdomain
57+
type = "CNAME"
58+
proxied = true
59+
ttl = 1
60+
}
61+
62+
63+
64+
8265
# --- 4. The DNS & Routing ---
8366
resource "cloudflare_workers_route" "catch_all" {
8467
zone_id = var.zone_id
8568
pattern = "pywire.dev/*"
8669
script = cloudflare_workers_script.router.script_name
8770
}
71+
72+
resource "cloudflare_workers_route" "nightly" {
73+
zone_id = var.zone_id
74+
pattern = "nightly.pywire.dev/*"
75+
script = cloudflare_workers_script.router.script_name
76+
}
77+
78+
# --- 5. Email Routing Setup ---
79+
80+
resource "cloudflare_email_routing_settings" "main" {
81+
zone_id = var.zone_id
82+
}
83+
84+
85+
86+
# Destination Registration
87+
# Helper to find every unique email address across both variables
88+
locals {
89+
all_unique_emails = distinct(concat(
90+
values(var.forwarding_rules),
91+
var.maintainer_emails
92+
))
93+
}
94+
95+
# Register every email found in your variables
96+
resource "cloudflare_email_routing_address" "destinations" {
97+
for_each = toset(local.all_unique_emails)
98+
account_id = var.account_id
99+
email = each.value
100+
}
101+
102+
# Individual Rules
103+
resource "cloudflare_email_routing_rule" "individual_aliases" {
104+
for_each = var.forwarding_rules
105+
106+
zone_id = var.zone_id
107+
name = "Forward: ${each.key}@"
108+
enabled = true
109+
110+
matchers = [{
111+
type = "literal"
112+
field = "to"
113+
value = "${each.key}@pywire.dev"
114+
}]
115+
116+
actions = [{
117+
type = "forward"
118+
# Look up the verified address resource
119+
value = [cloudflare_email_routing_address.destinations[each.value].email]
120+
}]
121+
}
122+
123+
# The Maintainers Group Rule
124+
resource "cloudflare_email_routing_rule" "maintainers_group" {
125+
zone_id = var.zone_id
126+
name = "Group: Maintainers"
127+
enabled = true
128+
129+
matchers = [{
130+
type = "literal"
131+
field = "to"
132+
value = "maintainers@pywire.dev"
133+
}]
134+
135+
actions = [{
136+
type = "forward"
137+
# Dynamically grab the verified email ID for everyone in the list
138+
value = [
139+
for email in var.maintainer_emails :
140+
cloudflare_email_routing_address.destinations[email].email
141+
]
142+
}]
143+
}

infra/variables.tf

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
variable "account_id" {
2+
type = string
3+
}
4+
5+
variable "cloudflare_api_token" {
6+
type = string
7+
sensitive = true
8+
}
9+
10+
variable "zone_id" {
11+
type = string
12+
}
13+
14+
variable "forwarding_rules" {
15+
description = "Map of alias to destination (1-to-1). Example: { 'hello' = 'me@fastmail.com' }"
16+
type = map(string)
17+
}
18+
19+
variable "maintainer_emails" {
20+
description = "List of emails that receive the 'maintainers@' broadcast"
21+
type = list(string)
22+
}

worker/src/index.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ export default {
33
const url = new URL(request.url);
44
const path = url.pathname;
55

6+
// --- 0. DETERMINE ENVIRONMENT ---
7+
const hostname = url.hostname;
8+
const isNightly = hostname.startsWith("nightly.");
9+
10+
// Define base targets based on environment
11+
const landingTarget = isNightly ? "nightly.pywire-landing.pages.dev" : "pywire-landing.pages.dev";
12+
const docsTarget = isNightly ? "nightly.pywire-docs.pages.dev" : "pywire-docs.pages.dev";
13+
614
// --- 1. HANDLE SHORTCUT REDIRECTS ---
715
const redirects = {
816
// "/discord": "https://discord.gg/pywire", // Update this!
@@ -39,10 +47,10 @@ export default {
3947
if (path.startsWith("/docs")) {
4048
// Strip "/docs" so the origin sees "/_astro/..." or "/"
4149
const newPath = path.replace(/^\/docs/, "") || "/";
42-
return proxy("pywire-docs.pages.dev", newPath);
50+
return proxy(docsTarget, newPath);
4351
}
4452

4553
// --- 4. ROUTE TO LANDING ---
46-
return proxy("pywire-landing.pages.dev");
54+
return proxy(landingTarget);
4755
},
4856
};

0 commit comments

Comments
 (0)