feat: Reconfigure CI for review environments (#6)

This pull request refactors and improves the GitHub Actions CI/CD workflow setup and enhances the application header component. The changes consolidate and clarify deployment workflows for production and review environments, improve environment variable handling, and update the application UI for greater flexibility.

**CI/CD Workflow Refactoring and Improvements:**

* Consolidated the CI workflow in `.github/workflows/ci.yml` to support both manual and reusable workflow triggers, making it easier to compose in other workflows.
* Removed the old deployment workflows (`fly-deploy.yml` and `fly-review.yml`) in favor of new, clearer workflows for production (`production.yml`) and review apps (`review.yml`). These new workflows use reusable CI steps, improved secret management, and explicit environment configuration [[1]](diffhunk://#diff-e98bb23501189d64a1cee3fab4260cfa5fb4e0bf50a7352fc8c4bfe1939f92c2L1-L18) [[2]](diffhunk://#diff-360ed408b1160aff40b11529c2471f642a393cfd9375757bf6d4da2c7ab78db7L1-L34) [[3]](diffhunk://#diff-d5171f9b8c42863b1e934fda1fefedf968913c65aa5d715555a696fb3cbd4c7eR1-R45) [[4]](diffhunk://#diff-ebc21ccd816b27c07389e15ad88c9e74b71bde5e8e315e4e30902097d38386e5R1-R66).
* Added a new `fly.review.toml` configuration file to standardize review app deployments on Fly.io, specifying build, deploy, environment, and VM settings.
* Updated `fly.toml` to explicitly specify the Dockerfile for builds, improving deployment reliability.

**Environment and Configuration Handling:**

* Changed the application to require the `PHX_HOST` environment variable at runtime, raising an error if it is missing. This ensures correct host configuration for all deployments.

**UI Component Enhancement:**

* Refactored the `app_header` component to accept customizable `title` and `icon` attributes, and updated its usage in the main layout to display "Spazio Solazzo" with a sun icon. This makes the header more flexible and visually consistent [[1]](diffhunk://#diff-4b44e6943316f34ab5bf0f9ea1956fd2a65dc8a7cbb9c5a381578c13c6e559f6L42-R42) [[2]](diffhunk://#diff-4b44e6943316f34ab5bf0f9ea1956fd2a65dc8a7cbb9c5a381578c13c6e559f6R119-R138).
This commit is contained in:
Víctor Martínez 2026-01-14 14:50:25 +01:00 committed by GitHub
commit 4cfa89ef21
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 163 additions and 62 deletions

View file

@ -1,10 +1,8 @@
name: CI
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
workflow_dispatch: {}
workflow_call:
permissions:
contents: read

View file

@ -1,18 +0,0 @@
# See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/
name: Fly Deploy
on:
push:
branches:
- main
jobs:
deploy:
name: Deploy app
runs-on: ubuntu-latest
concurrency: deploy-group # optional: ensure only one action runs at a time
steps:
- uses: actions/checkout@v4
- uses: superfly/flyctl-actions/setup-flyctl@master
- run: flyctl deploy --remote-only
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}

View file

@ -1,34 +0,0 @@
name: Deploy Review App
on:
# Run this workflow on every PR event. Existing review apps will be updated when the PR is updated.
pull_request:
types: [opened, reopened, synchronize, closed]
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
FLY_REGION: ams
FLY_ORG: personal
jobs:
review_app:
runs-on: ubuntu-latest
outputs:
url: ${{ steps.deploy.outputs.url }}
# Only run one deployment at a time per PR.
concurrency:
group: pr-${{ github.event.number }}
# Deploying apps with this "review" environment allows the URL for the app to be displayed in the PR UI.
# Feel free to change the name of this environment.
environment:
name: review
# The script in the `deploy` sets the URL output for each review app.
url: ${{ steps.deploy.outputs.url }}
steps:
- name: Get code
uses: actions/checkout@v4
- name: Deploy PR app to Fly.io
id: deploy
uses: superfly/fly-pr-review-apps@1.2.0

45
.github/workflows/production.yml vendored Normal file
View file

@ -0,0 +1,45 @@
# See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/
name: Production CI
on:
push:
branches:
- main
jobs:
ci:
uses: ./.github/workflows/ci.yml
secrets: inherit
deploy:
name: Deploy app
needs: ci
runs-on: ubuntu-latest
concurrency: deploy-group # optional: ensure only one action runs at a time
environment:
name: production
steps:
- uses: actions/checkout@v4
- uses: superfly/flyctl-actions/setup-flyctl@master
- name: Set Fly secrets
run: |
flyctl secrets set \
TOKEN_SIGNING_SECRET="$TOKEN_SIGNING_SECRET" \
ADMIN_EMAIL="$ADMIN_EMAIL" \
SPAZIO_SOLAZZO_EMAIL="$SPAZIO_SOLAZZO_EMAIL" \
FRONT_OFFICE_PHONE_NUMBER="$FRONT_OFFICE_PHONE_NUMBER" \
RESEND_API_KEY="$RESEND_API_KEY" \
DATABASE_URL="$DATABASE_URL"
env:
TOKEN_SIGNING_SECRET: ${{ secrets.TOKEN_SIGNING_SECRET }}
ADMIN_EMAIL: ${{ secrets.ADMIN_EMAIL }}
SPAZIO_SOLAZZO_EMAIL: ${{ secrets.SPAZIO_SOLAZZO_EMAIL }}
FRONT_OFFICE_PHONE_NUMBER: ${{ secrets.FRONT_OFFICE_PHONE_NUMBER }}
RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
- run: flyctl deploy --remote-only
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}

66
.github/workflows/review.yml vendored Normal file
View file

@ -0,0 +1,66 @@
name: Deploy Review App
on:
# Run this workflow on every PR event. Existing review apps will be updated when the PR is updated.
pull_request:
types: [opened, reopened, synchronize, closed]
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
FLY_REGION: ams
FLY_ORG: personal
APP_NAME: pr-${{ github.event.pull_request.number }}-jasterv-spazio-solazzo
jobs:
ci:
uses: ./.github/workflows/ci.yml
secrets: inherit
review_app:
runs-on: ubuntu-latest
needs: ci
outputs:
url: ${{ steps.deploy.outputs.url }}
# Only run one deployment at a time per PR.
concurrency:
group: pr-${{ github.event.number }}
# Deploying apps with this "review" environment allows the URL for the app to be displayed in the PR UI.
# Feel free to change the name of this environment.
environment:
name: review
# The script in the `deploy` sets the URL output for each review app.
url: ${{ steps.deploy.outputs.url }}
steps:
- name: Get code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Install flyctl CLI
uses: superfly/flyctl-actions/setup-flyctl@master
- name: Authenticate with Fly.io registry
run: flyctl auth docker
- name: Create Fly App before pushing docker image to registry
run: |
flyctl apps create ${{ env.APP_NAME }} --org ${{ env.FLY_ORG }} || true
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
push: true
tags: registry.fly.io/${{ env.APP_NAME }}:1.19
context: .
- name: Deploy PR app to Fly.io
id: deploy
uses: superfly/fly-pr-review-apps@1.5.0
with:
name: ${{ env.APP_NAME }}
config: fly.review.toml
secrets: |
TOKEN_SIGNING_SECRET=${{ secrets.TOKEN_SIGNING_SECRET }}
ADMIN_EMAIL=${{ secrets.ADMIN_EMAIL }}
SPAZIO_SOLAZZO_EMAIL=${{ secrets.SPAZIO_SOLAZZO_EMAIL }}
FRONT_OFFICE_PHONE_NUMBER=${{ secrets.FRONT_OFFICE_PHONE_NUMBER }}
RESEND_API_KEY=${{ secrets.RESEND_API_KEY }}
DATABASE_URL=${{ secrets.DATABASE_URL }}
SECRET_KEY_BASE=${{ secrets.SECRET_KEY_BASE }}
PHX_HOST=${{ env.APP_NAME }}.fly.dev

View file

@ -54,7 +54,9 @@ else
You can generate one by calling: mix phx.gen.secret
"""
host = System.get_env("PHX_HOST") || "example.com"
host =
System.get_env("PHX_HOST") ||
raise "Missing environment variable `PHX_HOST`!"
config :spazio_solazzo, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY")

34
fly.review.toml Normal file
View file

@ -0,0 +1,34 @@
# fly.review.toml
#
app = "spazio-solazzo"
primary_region = "ams"
kill_signal = "SIGTERM"
[build]
[deploy]
release_command = '/app/bin/migrate'
wait_timeout = "10m"
[env]
PHX_SERVER = "true"
PORT = "8080"
[http_service]
internal_port = 8080
force_https = true
auto_stop_machines = 'stop'
auto_start_machines = true
min_machines_running = 0
processes = ["app"]
[http_service.concurrency]
type = "connections"
soft_limit = 500
hard_limit = 500
[[vm]]
cpu_kind = "shared"
memory = '512mb'
cpus = 1
memory_mb = 512

View file

@ -8,6 +8,7 @@ primary_region = 'ams'
kill_signal = 'SIGTERM'
[build]
dockerfile = "Dockerfile"
[deploy]
release_command = '/app/bin/migrate'

View file

@ -39,7 +39,7 @@ defmodule SpazioSolazzoWeb.Layouts do
def app(assigns) do
~H"""
<.app_header current_user={@current_user} />
<.app_header current_user={@current_user} title="Spazio Solazzo" icon="hero-sun-solid" />
<main class="bg-slate-50 dark:bg-slate-900 flex-1 relative transition-colors duration-300">
{render_slot(@inner_block)}
@ -116,19 +116,26 @@ defmodule SpazioSolazzoWeb.Layouts do
"""
end
attr :title, :string, default: nil, doc: "the title shown on the top left of the header"
attr :icon, :string, default: nil, doc: "The icon shown on the top left of the header"
attr :current_user, :map,
default: nil,
doc: "the current authenticated user"
defp app_header(assigns) do
~H"""
<header class="sticky top-0 z-50 w-full border-b border-slate-200 dark:border-slate-800 bg-white/80 dark:bg-slate-900/80 backdrop-blur-md px-6 py-4">
<div class="mx-auto flex h-10 max-w-[1200px] items-center justify-between">
<.link
navigate="/"
class="flex items-center gap-4 text-slate-900 dark:text-slate-100 hover:opacity-80 transition-opacity"
class="flex items-center gap-3 text-slate-900 dark:text-slate-100 hover:opacity-80 transition-opacity"
>
<div class="flex items-center justify-center size-8 bg-sky-500 rounded-lg text-white shadow-lg shadow-sky-500/20">
<.icon name="hero-squares-2x2" class="size-5" />
<div class="flex items-center justify-center text-sky-500">
<.icon name={@icon} class="size-8" />
</div>
<h2 class="text-lg font-bold leading-tight tracking-tight text-slate-800 dark:text-slate-100">
Spazio Solazzo
{@title}
</h2>
</.link>