Skip to content
Open
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
10 changes: 10 additions & 0 deletions .github/workflows/_bake-and-push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ on:
required: false
PAYLOAD_SECRET:
required: false
PAYLOAD_SECRET_KEY:
required: false
# Not a genuine secret (Sentry DSNs are inlined into the public client
# bundle by design) but plumbed as one because it's stored as a GitHub
# Secret today; going through --mount=type=secret keeps it unlogged
# without needing a GitHub Variable migration.
NEXT_PUBLIC_SENTRY_DSN:
required: false
SENTRY_AUTH_TOKEN:
required: false
SENTRY_ORG:
Expand Down Expand Up @@ -126,6 +134,8 @@ jobs:
BUILD_DATE: ${{ steps.meta.outputs.date }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
PAYLOAD_SECRET: ${{ secrets.PAYLOAD_SECRET }}
PAYLOAD_SECRET_KEY: ${{ secrets.PAYLOAD_SECRET_KEY }}
NEXT_PUBLIC_SENTRY_DSN: ${{ secrets.NEXT_PUBLIC_SENTRY_DSN }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
Expand Down
79 changes: 79 additions & 0 deletions .github/workflows/_build-charterafrica.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Reusable Build | charterAFRICA

on:
workflow_call:
inputs:
tag:
required: true
type: string
description: "Image tag to build or push"
push:
required: true
type: boolean
description: "Whether to push the built image to the registry"
base_tag:
required: true
type: string
description: "Published base image tag to build from"
app_url:
required: true
type: string
description: "NEXT_PUBLIC_APP_URL baked into the client bundle (public, not a secret)"
sentry_environment:
required: true
type: string
description: "Sentry environment baked into the app"
seo_disabled:
required: false
type: string
default: "true"
description: "NEXT_PUBLIC_SEO_DISABLED baked into the client bundle"
set:
required: false
type: string
default: ""
description: "Additional bake --set overrides"
secrets:
DOCKER_HUB_USERNAME:
required: false
DOCKER_HUB_ACCESS_TOKEN:
required: false
DATABASE_URL:
required: false
PAYLOAD_SECRET_KEY:
required: false
NEXT_PUBLIC_SENTRY_DSN:
required: false
SENTRY_AUTH_TOKEN:
required: false
SENTRY_ORG:
required: false
SENTRY_PROJECT:
required: false

jobs:
build:
permissions:
actions: read
contents: read
uses: ./.github/workflows/_bake-and-push.yml
with:
target: charterafrica
target_os: '["ubuntu-24.04-arm"]'
base_tag: ${{ inputs.base_tag }}
tag: ${{ inputs.tag }}
push: ${{ inputs.push }}
set: |
charterafrica.args.NEXT_PUBLIC_APP_URL=${{ inputs.app_url }}
charterafrica.args.SENTRY_ENVIRONMENT=${{ inputs.sentry_environment }}
charterafrica.args.NEXT_PUBLIC_SEO_DISABLED=${{ inputs.seo_disabled }}
${{ inputs.set }}
secrets:
DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }}
DOCKER_HUB_ACCESS_TOKEN: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
PAYLOAD_SECRET_KEY: ${{ secrets.PAYLOAD_SECRET_KEY }}
NEXT_PUBLIC_SENTRY_DSN: ${{ secrets.NEXT_PUBLIC_SENTRY_DSN }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
136 changes: 136 additions & 0 deletions .github/workflows/charterafrica.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
name: charterAFRICA

on:
push:
branches:
- main
paths:
- "apps/charterafrica/**"
- "docker/apps/charterafrica/**"
- "docker-bake.hcl"
- ".github/workflows/_bake-and-push.yml"
- ".github/workflows/_build-charterafrica.yml"
- ".github/workflows/charterafrica.yml"

permissions:
actions: read
contents: read

concurrency:
group: "${{ github.workflow }} @ ${{ github.ref }}"
cancel-in-progress: true

jobs:
# Checks whether apps/charterafrica/package.json has a version bump.
# The prod build/deploy is gated on this; dev builds on every push.
version-check:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-24.04]
permissions:
contents: read
outputs:
changed: ${{ steps.check.outputs.changed }}
version: ${{ steps.check.outputs.version }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0

- uses: actions/setup-node@v6
with:
node-version-file: "package.json"

- name: Check if version is bumped
id: check
uses: EndBug/version-check@v3
with:
diff-search: true
file-name: apps/charterafrica/package.json

# Builds the DEV image and pushes it to DockerHub on every push. Matches
# the pre-bake workflow this replaces: there's no DEV Dokku app for
# charterafrica yet, so this only validates and publishes the image.
#
# Required GitHub Secrets:
# CHARTERAFRICA_MONGO_URL, CHARTERAFRICA_PAYLOAD_SECRET_KEY,
# CHARTERAFRICA_SENTRY_DSN, CHARTERAFRICA_SENTRY_PROJECT,
# SENTRY_AUTH_TOKEN, SENTRY_ORG, UI_BASE_TAG (var)
build-dev:
permissions:
actions: read
contents: read
uses: ./.github/workflows/_build-charterafrica.yml
with:
base_tag: ${{ vars.UI_BASE_TAG }}
tag: ${{ github.sha }}
push: true
app_url: "https://charterafrica.dev.codeforafrica.org"
sentry_environment: development
secrets:
DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }}
DOCKER_HUB_ACCESS_TOKEN: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
DATABASE_URL: ${{ secrets.CHARTERAFRICA_MONGO_URL }}
PAYLOAD_SECRET_KEY: ${{ secrets.CHARTERAFRICA_PAYLOAD_SECRET_KEY }}
NEXT_PUBLIC_SENTRY_DSN: ${{ secrets.CHARTERAFRICA_SENTRY_DSN }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.CHARTERAFRICA_SENTRY_PROJECT }}

# TODO: No DEV Dokku app exists for charterafrica yet.
# Enable this job (remove `if: false`) when the app is created on ui-1.dev
# and update the git_remote_url below.
deploy-dev:
if: false
needs: build-dev
permissions: {}
uses: ./.github/workflows/push-to-dokku.yml
with:
git_remote_url: "ssh://azureuser@ui-1.dev.codeforafrica.org/charterafrica-ui"
deploy_docker_image: "codeforafrica/charterafrica:${{ github.sha }}"
secrets:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}

# Builds the PROD image only when the package.json version is bumped,
# using the PROD canonical URL and the semver tag.
build-prod:
needs: version-check
if: needs.version-check.outputs.changed == 'true'
permissions:
actions: read
contents: read
uses: ./.github/workflows/_build-charterafrica.yml
with:
base_tag: ${{ vars.UI_BASE_TAG }}
tag: ${{ needs.version-check.outputs.version }}
push: true
app_url: "https://charter.africa"
sentry_environment: production
seo_disabled: "false"
set: |
charterafrica.tags+=codeforafrica/charterafrica:latest
secrets:
DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }}
DOCKER_HUB_ACCESS_TOKEN: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
DATABASE_URL: ${{ secrets.CHARTERAFRICA_MONGO_URL }}
PAYLOAD_SECRET_KEY: ${{ secrets.CHARTERAFRICA_PAYLOAD_SECRET_KEY }}
NEXT_PUBLIC_SENTRY_DSN: ${{ secrets.CHARTERAFRICA_SENTRY_DSN }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.CHARTERAFRICA_SENTRY_PROJECT }}

# TODO: No PROD Dokku app exists for charterafrica yet either — confirm
# whether it should point to a different server (e.g. a different AWS
# account) before enabling this, matching the pre-bake workflow's own
# unresolved TODO.
deploy-prod:
if: false
needs: [version-check, build-prod]
permissions: {}
uses: ./.github/workflows/push-to-dokku.yml
with:
git_remote_url: "ssh://dokku@ui-1.prod.codeforafrica.org/charterafrica-ui"
deploy_docker_image: "codeforafrica/charterafrica:${{ needs.version-check.outputs.version }}"
secrets:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
30 changes: 30 additions & 0 deletions .github/workflows/pr-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths:
- "apps/charterafrica/**"
- "apps/pesayetu/**"
- "apps/roboshield/**"
- "apps/techlabblog/**"
- "apps/trustlab/**"
- "docker/apps/charterafrica/**"
- "docker/apps/pesayetu/**"
- "docker/apps/roboshield/**"
- "docker/apps/techlabblog/**"
Expand All @@ -22,10 +24,12 @@ on:
- "scripts/pr-build-targets.mjs"
- "scripts/pr-build-targets.test.mjs"
- ".github/workflows/_bake-and-push.yml"
- ".github/workflows/_build-charterafrica.yml"
- ".github/workflows/_build-pesayetu.yml"
- ".github/workflows/_build-roboshield.yml"
- ".github/workflows/_build-techlabblog.yml"
- ".github/workflows/_build-trustlab.yml"
- ".github/workflows/charterafrica.yml"
- ".github/workflows/pesayetu.yml"
- ".github/workflows/pr-build.yml"
- ".github/workflows/roboshield.yml"
Expand Down Expand Up @@ -99,6 +103,32 @@ jobs:
--base "${{ github.event.pull_request.base.sha }}" \
--head "${{ github.event.pull_request.head.sha }}"

build-charterafrica:
name: Build charterafrica image
needs: affected
if: ${{ contains(fromJSON(needs.affected.outputs.targets), 'charterafrica') }}
permissions:
actions: read
contents: read
uses: ./.github/workflows/_build-charterafrica.yml
with:
base_tag: ${{ vars.UI_BASE_TAG }}
tag: pr-${{ github.event.pull_request.number }}-${{ github.sha }}
push: false
app_url: "http://localhost:3000"
sentry_environment: ci
secrets:
# The custom server connects to MongoDB via payload.init() before
# spawning `next build`, so — like the other Payload-backed migrated
# apps — PR builds need a genuinely reachable database, not a dummy
# value.
DATABASE_URL: ${{ secrets.CHARTERAFRICA_MONGO_URL }}
PAYLOAD_SECRET_KEY: pr-build-unused
NEXT_PUBLIC_SENTRY_DSN: pr-build-unused
SENTRY_AUTH_TOKEN: pr-build-unused
SENTRY_ORG: pr-build-unused
SENTRY_PROJECT: pr-build-unused

build-pesayetu:
name: Build pesayetu image
needs: affected
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ COMPOSE_BUILD_ENV=BUILDKIT_PROGRESS=plain
.PHONY: charterafrica civicsignalblog climatemappedafrica codeforafrica down mongodb mongodb-keyfile pesayetu roboshield techlabblog trustlab twoopstracker vpnmanager

charterafrica:
./scripts/dc.sh charterafrica
./scripts/bake-up.sh charterafrica

civicsignalblog:
./scripts/dc.sh civicsignalblog
Expand Down
2 changes: 1 addition & 1 deletion apps/charterafrica/.env.template
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Required
# --------
MONGO_URL
DATABASE_URL

PAYLOAD_CORS
PAYLOAD_CSRF
Expand Down
2 changes: 1 addition & 1 deletion apps/charterafrica/migrate-mongo-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ require("dotenv").config({ path: "./.env" });

const config = {
mongodb: {
url: process.env.MONGO_URL,
url: process.env.DATABASE_URL,
options: {
useNewUrlParser: true,
useUnifiedTopology: true,
Expand Down
2 changes: 1 addition & 1 deletion apps/charterafrica/payload.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export default buildConfig({
admin: "/admin",
},
db: mongooseAdapter({
url: process.env.MONGO_URL,
url: process.env.DATABASE_URL,
migrationDir: process.env.MIGRATIONS_DIR,
}),
collections: [
Expand Down
4 changes: 2 additions & 2 deletions apps/charterafrica/turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"outputs": [".next/**", "!.next/cache/**", "dist/**"],
"env": [
"AIRTABLE_API_TOKEN",
"MONGO_URL",
"DATABASE_URL",
"NEXT_BUILD",
"NEXT_HOSTNAME",
"NEXT_MANUAL_SIG_HANDLE",
Expand Down Expand Up @@ -41,8 +41,8 @@
"env": [
"AIRTABLE_API_TOKEN",
"CHARTERAFRICA_SENTRY_DSN",
"DATABASE_URL",
"GOOGLE_API_KEY",
"MONGO_URL",
"NEXT_BUILD",
"NEXT_HOSTNAME",
"NODE_ENV",
Expand Down
21 changes: 20 additions & 1 deletion docker-bake.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ group "base" {
}

group "apps" {
targets = ["pesayetu", "roboshield", "techlabblog", "trustlab"]
targets = ["charterafrica", "pesayetu", "roboshield", "techlabblog", "trustlab"]
}

# Prefer explicit targets/groups for predictability.
Expand Down Expand Up @@ -160,6 +160,25 @@ target "_payload-app-runner" {
]
}

target "charterafrica" {
inherits = ["_app-runner"]
dockerfile = "docker/apps/charterafrica/Dockerfile"
tags = ["${REGISTRY}charterafrica:${TAG}"]
args = {
NEXT_PUBLIC_APP_URL = "${NEXT_PUBLIC_APP_URL}"
SENTRY_ENVIRONMENT = "${SENTRY_ENVIRONMENT}"
}
# sentry_auth_token/org/project are inherited from _app. database_url,
# payload_secret_key, and next_public_sentry_dsn are charterafrica-specific
# — it reads PAYLOAD_SECRET_KEY (not PAYLOAD_SECRET like _payload-app-runner
# provides), so this declares its own secret list rather than inheriting it.
secret = [
"type=env,id=database_url,env=DATABASE_URL",
"type=env,id=payload_secret_key,env=PAYLOAD_SECRET_KEY",
"type=env,id=next_public_sentry_dsn,env=NEXT_PUBLIC_SENTRY_DSN",
]
}

# pesayetu fetches content from WordPress (WPGraphQL) during static generation,
# so these are real build args, not just runtime config. They default to empty
# so the image still builds without them; pages that depend on WordPress data
Expand Down
Loading