Skip to content

Commit

Permalink
🤖 Daggerize & deploy to Fly.io ✈️
Browse files Browse the repository at this point in the history
TL;DR the app is currently running as https://changelog-nightly-2023-10-10.fly.dev/

This adds everything needed to run this app on Fly.io:
- [x] a Dagger pipeline captured as Go code
- [x] GitHub Actions workflow that runs the Dagger pipeline
- [x] `nginx.conf` used to serve the static files
- [x] `supercronic` to run the `crontab` (now versioned in this repo!)
  - includes Sentry.io cron integration via `SENTRY_DSN`
- [x] `Procfile` support so that the Fly app runs both nginx & supercronic
  - hi `foreman`, old friend!
- [ ] 1Password service account integration

A good command to start with is `dagger run go run . build`

Use the `--debug` flag to build a local image. Requires these files to be
present locally:
- `.env`
- `bq-key.p12`
- `github.db`

The local image will be exported to `tmp/image.tar`. Test it locally by
running:

  docker load -i tmp/image.tar
  docker run --rm -p 8081:80 -it <sha256:...>

To see all available options, run: `dagger run go run .`

This was done part of thechangelog/changelog.com#480

Signed-off-by: Gerhard Lazu <[email protected]>
  • Loading branch information
gerhard committed Oct 10, 2023
1 parent 8f7458e commit fca033d
Show file tree
Hide file tree
Showing 14 changed files with 643 additions and 1 deletion.
32 changes: 32 additions & 0 deletions .github/workflows/ship_it.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: "Ship It!"

concurrency:
# There should only be able one running job per repository / branch combo.
# We do not want multiple deploys running in parallel.
group: ${{ github.repository }}-${{ github.ref_name }}

on:
push:
branches:
- 'master'
- 'daggerize'
pull_request:
workflow_dispatch:

jobs:
dagger:
runs-on: ubuntu-latest
steps:
- name: "Checkout code..."
uses: actions/checkout@v3

- name: "Setup Go..."
uses: actions/setup-go@v4
with:
go-version: "1.20"

- name: "Ship it!"
env:
FLY_API_TOKEN: "${{ secrets.FLY_API_TOKEN }}"
run: |
go run . cicd --app "${{ vars.APP }}"
1 change: 1 addition & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
ruby 2.3.3
flyctl 0.1.104
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ gem "sqlite3"
gem "rest-client"
gem "obscenity"
gem "whatlanguage"
gem "foreman"

group :test do
gem "rspec"
Expand Down
4 changes: 3 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ GEM
extlib (0.9.16)
faraday (0.10.1)
multipart-post (>= 1.2, < 3)
foreman (0.87.2)
google-api-client (0.8.6)
activesupport (>= 3.2)
addressable (~> 2.3)
Expand Down Expand Up @@ -124,6 +125,7 @@ DEPENDENCIES
bigquery
createsend
dotenv
foreman
gemoji!
hashie
obscenity
Expand All @@ -140,4 +142,4 @@ RUBY VERSION
ruby 2.3.3p222

BUNDLED WITH
1.13.6
1.14.6
2 changes: 2 additions & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
web: nginx
cron: supercronic -debug crontab
2 changes: 2 additions & 0 deletions crontab
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# generate/deliver Nightly at 9:59pm each night¬
59 21 * * * rake generate
21 changes: 21 additions & 0 deletions fly.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# https://fly.io/docs/reference/configuration/
app = "changelog-nightly-2023-10-10"
primary_region = "ord"

[env]
# used by supercronic - https://changelog-media.sentry.io/settings/projects/changelog-com/keys/
SENTRY_DSN = "https://[email protected]/5668962"

[mounts]
source = "changelog_nightly_2023_10_10"
destination = "/app/dist"

[http_service]
internal_port = 80
force_https = true

[[http_service.checks]]
method = "GET"
path = "/health"
interval = "5s"
timeout = "4s"
146 changes: 146 additions & 0 deletions flyio.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package main

import (
"fmt"
"os"
"strings"
"time"

"dagger.io/dagger"
)

type Flyio struct {
app string
deployWait string
publishedImageRef string
org string
pipeline *Pipeline
region string
registry string
token *dagger.Secret
version string
volume string
volumeSize string
}

func newFlyio(p *Pipeline) *Flyio {
token := os.Getenv("FLY_API_TOKEN")
if token == "" {
panic("FLY_API_TOKEN env var must be set")
}

f := &Flyio{
app: p.app,
deployWait: "60",
org: "changelog",
pipeline: p,
region: "ord",
registry: "registry.fly.io",
token: p.dag.SetSecret("FLY_API_TOKEN", token),
version: p.tools.Flyctl(),
volumeSize: "2",
}

f.volume = strings.ReplaceAll(f.app, "-", "_")

return f
}

func (f *Flyio) Cli() *dagger.Container {
container := f.pipeline.Container().Pipeline("fly.io").
From(fmt.Sprintf("flyio/flyctl:v%s", f.version)).
WithSecretVariable("FLY_API_TOKEN", f.token).
WithEnvVariable("RUN_AT", time.Now().String()).
WithNewFile("fly.toml", dagger.ContainerWithNewFileOpts{
Contents: f.Config(),
})

_, err := container.File("fly.toml").Export(f.pipeline.ctx, "fly.toml")
if err != nil {
panic(err)
}

return container
}

func (f *Flyio) Config() string {
return fmt.Sprintf(`# https://fly.io/docs/reference/configuration/
app = "%s"
primary_region = "%s"
[env]
# used by supercronic - https://changelog-media.sentry.io/settings/projects/changelog-com/keys/
SENTRY_DSN = "https://[email protected]/5668962"
[mounts]
source = "%s"
destination = "/app/dist"
[http_service]
internal_port = 80
force_https = true
[[http_service.checks]]
method = "GET"
path = "/health"
interval = "5s"
timeout = "4s"`, f.app, f.region, f.volume)
}

func (f *Flyio) App() *Flyio {
cli := f.Cli()

_, err := cli.
WithExec([]string{"status"}).
Sync(f.pipeline.ctx)
if err != nil {
_, err = cli.
WithExec([]string{"apps", "create", f.app, "--org", f.org}).
WithExec([]string{"volume", "create", f.volume, "--yes", "--region", f.region, "--size", f.volumeSize}).
Sync(f.pipeline.ctx)
if err != nil {
panic(err)
}
}

return f
}

func (f *Flyio) ImageRef() string {
gitSHA := os.Getenv("GITHUB_SHA")
if gitSHA == "" {
gitSHA = "dev"
}

return fmt.Sprintf("%s/%s:%s", f.registry, f.app, gitSHA)
}

func (f *Flyio) Publish() *Flyio {
var err error

f.publishedImageRef, err = f.pipeline.workspace.
Pipeline("publish").
WithRegistryAuth(f.registry, "x", f.token).
Publish(f.pipeline.ctx, f.ImageRef())
if err != nil {
panic(err)
}

return f
}

func (f *Flyio) Deploy() *Flyio {
_, err := f.Cli().Pipeline("deploy").
WithExec([]string{
"deploy", "--now",
"--app", f.app,
"--image", f.publishedImageRef,
"--wait-timeout", f.deployWait,
}).
Sync(f.pipeline.ctx)
if err != nil {
panic(err)
}

return f
}
22 changes: 22 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module github.com/thechangelog/nightly

go 1.20

require (
dagger.io/dagger v0.8.7
github.com/urfave/cli/v2 v2.25.7
)

require (
github.com/99designs/gqlgen v0.17.31 // indirect
github.com/Khan/genqlient v0.6.0 // indirect
github.com/adrg/xdg v0.4.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/iancoleman/strcase v0.3.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/vektah/gqlparser/v2 v2.5.6 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.12.0 // indirect
)
53 changes: 53 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
dagger.io/dagger v0.8.7 h1:3wGzK9RKjLcNk5AnIYqkO7TzIJyftb8fT+h0WM9chAM=
dagger.io/dagger v0.8.7/go.mod h1:DbJi6aSXaRLuio0lHlnpNxfuAL5uMJvRy4UIytmbtLo=
github.com/99designs/gqlgen v0.17.31 h1:VncSQ82VxieHkea8tz11p7h/zSbvHSxSDZfywqWt158=
github.com/99designs/gqlgen v0.17.31/go.mod h1:i4rEatMrzzu6RXaHydq1nmEPZkb3bKQsnxNRHS4DQB4=
github.com/Khan/genqlient v0.6.0 h1:Bwb1170ekuNIVIwTJEqvO8y7RxBxXu639VJOkKSrwAk=
github.com/Khan/genqlient v0.6.0/go.mod h1:rvChwWVTqXhiapdhLDV4bp9tz/Xvtewwkon4DpWWCRM=
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
github.com/vektah/gqlparser/v2 v2.5.6 h1:Ou14T0N1s191eRMZ1gARVqohcbe1e8FrcONScsq8cRU=
github.com/vektah/gqlparser/v2 v2.5.6/go.mod h1:z8xXUff237NntSuH8mLFijZ+1tjV1swDbpDqjJmk6ME=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Loading

0 comments on commit fca033d

Please sign in to comment.