Skip to content

Commit

Permalink
feat: preview environments and automated deployments
Browse files Browse the repository at this point in the history
  • Loading branch information
zackpollard committed Nov 28, 2024
1 parent 98f710a commit 4343fc4
Show file tree
Hide file tree
Showing 19 changed files with 406 additions and 0 deletions.
73 changes: 73 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
tofu_version: '1.7.1'
tg_version: '0.69.0'
ENVIRONMENT: ${{ github.ref == 'refs/heads/main' && 'prod' || 'dev' }}

jobs:
build:
name: Build
Expand All @@ -30,3 +35,71 @@ jobs:

- name: Run build
run: npm run build

- name: Upload build output
uses: actions/upload-artifact@v4
with:
name: build-output
path: build
retention-days: 1

deploy:
name: Deploy
runs-on: ubuntu-latest
needs: build
env:
TF_VAR_stage: ${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.number) || '' }}
OP_SERVICE_ACCOUNT_TOKEN: ${{ github.ref == 'refs/heads/main' && secrets.OP_TF_PROD_ENV || secrets.OP_TF_DEV_ENV }}
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: 'Get build artifact'
uses: actions/download-artifact@v4
with:
name: 'build-output'
path: '${{ github.workspace }}/build'

- name: Install 1Password CLI
uses: 1password/install-cli-action@v1

- name: Install Terragrunt
uses: eLco/setup-terragrunt@v1
with:
terragrunt_version: ${{ env.tg_version }}

- name: 'Install OpenTofu'
uses: opentofu/setup-opentofu@v1
with:
tofu_version: ${{ env.tofu_version }}
tofu_wrapper: false

- name: Deploy All
working-directory: ${{ github.workspace }}/deployment
run: op run --env-file=".env" -- terragrunt run-all apply --terragrunt-non-interactive

- name: Cloudflare Deploy Output
id: deploy-output
working-directory: ${{ github.workspace }}/deployment/modules/cloudflare/static-pages
run: |
echo "output=$(op run --no-masking --env-file='../../../.env' -- terragrunt output -json | jq -c .)" >> $GITHUB_OUTPUT
- name: Publish Frontend to Cloudflare Pages
uses: cloudflare/pages-action@v1
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN_PAGES_UPLOAD }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: ${{ fromJson(steps.deploy-output.outputs.output).pages_project_name.value }}
directory: 'build'
branch: ${{ fromJson(steps.deploy-output.outputs.output).pages_branch.value }}
wranglerVersion: '3'

- name: Comment
uses: actions-cool/maintain-one-comment@v3
if: ${{ github.event_name == 'pull_request' }}
with:
number: ${{ github.event.number }}
body: |
📖 Preview of ui.immich.app deployed to [${{ fromJson(steps.deploy-output.outputs.output).immich_subdomain.value }}](https://${{ fromJson(steps.deploy-output.outputs.output).immich_subdomain.value }})
emojis: 'rocket'
body-include: '<!-- ui PR URL -->'
51 changes: 51 additions & 0 deletions .github/workflows/destroy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Destroy
on:
pull_request_target:
types: [closed]

env:
tofu_version: '1.7.1'
tg_version: '0.69.0'

jobs:
deploy:
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 1
matrix:
environment: ['dev', 'prod']
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install 1Password CLI
uses: 1password/install-cli-action@v1

- name: Install Terragrunt
uses: eLco/setup-terragrunt@v1
with:
terragrunt_version: ${{ env.tg_version }}

- name: 'Install OpenTofu'
uses: opentofu/setup-opentofu@v1
with:
tofu_version: ${{ env.tofu_version }}
tofu_wrapper: false

- name: Destroy All
working-directory: ${{ env.working_dir }}
env:
ENVIRONMENT: ${{ matrix.environment }}
TF_VAR_dist_dir: ${{ github.workspace }}/build
TF_VAR_stage: pr-${{ github.event.number }}
OP_SERVICE_ACCOUNT_TOKEN: ${{ matrix.environment == 'prod' && secrets.OP_TF_PROD_ENV || secrets.OP_TF_DEV_ENV }}
working_dir: 'deployment'
run: op run --env-file=".env" -- terragrunt run-all destroy -refresh=false --terragrunt-non-interactive --terragrunt-exclude 'pages-project'

- name: Comment
uses: actions-cool/maintain-one-comment@v3
with:
number: ${{ github.event.number }}
delete: true
body-include: '<!-- web PR URL -->'
4 changes: 4 additions & 0 deletions deployment/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export TF_VAR_cloudflare_account_id="op://tf/cloudflare/account_id"
export TF_VAR_cloudflare_api_token="op://tf/cloudflare/api_token"
export TF_VAR_tf_state_postgres_conn_str="op://tf/tf_state/postgres_conn_str"
export TF_VAR_env=$ENVIRONMENT
40 changes: 40 additions & 0 deletions deployment/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# OpenTofu

!.env

# Local .terraform directories
**/.terraform/*

# .tfstate files
*.tfstate
*.tfstate.*

# Crash log files
crash.log
crash.*.log

# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json

# Include override files you do wish to add to version control using negated pattern
# !example_override.tf

# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*

# Ignore CLI configuration files
.terraformrc
terraform.rc

# Terragrunt

# terragrunt cache directories
**/.terragrunt-cache/*

# Terragrunt debug output file (when using `--terragrunt-debug` option)
# See: https://terragrunt.gruntwork.io/docs/reference/cli-options/#terragrunt-debug
terragrunt-debug.tfvars.json
25 changes: 25 additions & 0 deletions deployment/modules/cloudflare/pages-project/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions deployment/modules/cloudflare/pages-project/config.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
terraform {
backend "pg" {}
required_version = "~> 1.7"

required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "4.46.0"
}
}
}
3 changes: 3 additions & 0 deletions deployment/modules/cloudflare/pages-project/locals.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
locals {
app_name = "ui"
}
14 changes: 14 additions & 0 deletions deployment/modules/cloudflare/pages-project/pages.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module "pages_project" {
source = "git::https://github.com/immich-app/devtools.git//tf/shared/modules/cloudflare-pages-project?ref=feat/pages-project-tf-module"

cloudflare_api_token = data.terraform_remote_state.api_keys_state.outputs.terraform_key_cloudflare_account
cloudflare_account_id = data.terraform_remote_state.cloudflare_account.outputs.cloudflare_account_id

app_name = local.app_name
env = var.env
}

output "pages_project" {
value = module.pages_project.pages_project
sensitive = true
}
17 changes: 17 additions & 0 deletions deployment/modules/cloudflare/pages-project/remote-state.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
data "terraform_remote_state" "api_keys_state" {
backend = "pg"

config = {
conn_str = var.tf_state_postgres_conn_str
schema_name = "prod_cloudflare_api_keys"
}
}

data "terraform_remote_state" "cloudflare_account" {
backend = "pg"

config = {
conn_str = var.tf_state_postgres_conn_str
schema_name = "prod_cloudflare_account"
}
}
24 changes: 24 additions & 0 deletions deployment/modules/cloudflare/pages-project/terragrunt.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
terraform {
source = "."

extra_arguments custom_vars {
commands = get_terraform_commands_that_need_vars()
}
}

include {
path = find_in_parent_folders("state.hcl")
}

locals {
env = get_env("TF_VAR_env")
}

remote_state {
backend = "pg"

config = {
conn_str = get_env("TF_VAR_tf_state_postgres_conn_str")
schema_name = "cloudflare_pages_project_immich_app_ui_${local.env}"
}
}
2 changes: 2 additions & 0 deletions deployment/modules/cloudflare/pages-project/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
variable "tf_state_postgres_conn_str" {}
variable "env" {}
25 changes: 25 additions & 0 deletions deployment/modules/cloudflare/static-pages/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions deployment/modules/cloudflare/static-pages/config.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
terraform {
backend "pg" {}
required_version = "~> 1.7"

required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "4.46.0"
}
}
}
3 changes: 3 additions & 0 deletions deployment/modules/cloudflare/static-pages/locals.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
locals {
app_name = "ui"
}
28 changes: 28 additions & 0 deletions deployment/modules/cloudflare/static-pages/pages.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module "static_pages" {
source = "git::https://github.com/immich-app/devtools.git//tf/shared/modules/cloudflare-pages?ref=feat/pages-project-tf-module"

cloudflare_api_token = data.terraform_remote_state.api_keys_state.outputs.terraform_key_cloudflare_docs
cloudflare_account_id = data.terraform_remote_state.cloudflare_account.outputs.cloudflare_account_id

pages_project = data.terraform_remote_state.pages_project.outputs.pages_project

app_name = local.app_name
stage = var.stage
env = var.env
}

output "pages_branch" {
value = module.static_pages.pages_branch
}

output "immich_subdomain" {
value = module.static_pages.branch_subdomain
}

output "pages_branch_subdomain" {
value = module.static_pages.pages_branch_subdomain
}

output "pages_project_name" {
value = module.static_pages.pages_project_name
}
26 changes: 26 additions & 0 deletions deployment/modules/cloudflare/static-pages/remote-state.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
data "terraform_remote_state" "api_keys_state" {
backend = "pg"

config = {
conn_str = var.tf_state_postgres_conn_str
schema_name = "prod_cloudflare_api_keys"
}
}

data "terraform_remote_state" "cloudflare_account" {
backend = "pg"

config = {
conn_str = var.tf_state_postgres_conn_str
schema_name = "prod_cloudflare_account"
}
}

data "terraform_remote_state" "pages_project" {
backend = "pg"

config = {
conn_str = var.tf_state_postgres_conn_str
schema_name = "cloudflare_pages_project_immich_app_ui_${var.env}"
}
}
Loading

0 comments on commit 4343fc4

Please sign in to comment.