Skip to content

Commit

Permalink
Containerize nightly code
Browse files Browse the repository at this point in the history
Signed-off-by: Gerhard Lazu <gerhard@changelog.com>
  • Loading branch information
gerhard committed Oct 8, 2023
1 parent 8f7458e commit caa10f4
Show file tree
Hide file tree
Showing 4 changed files with 330 additions and 0 deletions.
33 changes: 33 additions & 0 deletions .github/workflows/ship_it.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
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'
- 'containerize'
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:
GHCR_USERNAME: "${{ vars.GHCR_USERNAME }}"
GHCR_PASSWORD: "${{ secrets.GHCR_PASSWORD }}"
run: |
go run main.go image
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=
222 changes: 222 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
package main

import (
"bufio"
"context"
"fmt"
"log"
"os"
"path/filepath"
"strings"
"time"

"dagger.io/dagger"
"github.com/urfave/cli/v2"
)

func main() {
ctx := context.Background()
dag, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stderr))
if err != nil {
panic(err)
}
defer dag.Close()

app := &cli.App{
Name: "nightly",
Usage: "Changelog Nightly CI/CD pipeline entrypoints",
Version: "v2023.09.30",
Compiled: time.Now(),
Authors: []*cli.Author{
{
Name: "Gerhard Lazu",
Email: "gerhard@changelog.com",
},
},
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "nocache",
Aliases: []string{"n"},
Usage: "Bust Dagger ops cache",
EnvVars: []string{"NOCACHE"},
},
&cli.BoolFlag{
Name: "debug",
Aliases: []string{"d"},
Usage: "Debug command",
EnvVars: []string{"DEBUG"},
},
&cli.StringFlag{
Name: "platform",
Aliases: []string{"p"},
Usage: "Runtime platform",
Value: "linux/amd64",
EnvVars: []string{"PLATFORM"},
},
},
Commands: []*cli.Command{
{
Name: "image",
Aliases: []string{"i"},
Usage: "Creates container image",
Action: func(cCtx *cli.Context) error {
pipeline := newPipeline(ctx, cCtx, dag)
pipeline.image().publish()
return nil
},
},
},
}

if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}

type Pipeline struct {
ctx context.Context
dag *dagger.Client
debug bool
nocache bool
platform string
workspace *dagger.Container
}

func newPipeline(ctx context.Context, cCtx *cli.Context, dag *dagger.Client) *Pipeline {
platform := cCtx.String("platform")

workspace := dag.Container(dagger.ContainerOpts{
Platform: dagger.Platform(platform),
})

return &Pipeline{
ctx: ctx,
platform: platform,
debug: cCtx.Bool("debug"),
nocache: cCtx.Bool("nocache"),
dag: dag,
workspace: workspace,
}
}

func (p *Pipeline) ok() *Pipeline {
var err error
p.workspace, err = p.workspace.Sync(p.ctx)
if err != nil {
panic(err)
}
return p
}

func (p *Pipeline) image() *Pipeline {
p.workspace = p.workspace.Pipeline("container image").
From(fmt.Sprintf("ruby:%s", currentToolVersions().Ruby())).
WithExec([]string{"ruby", "--version"})

if p.nocache {
p.workspace = p.workspace.WithEnvVariable("CACHE_BUSTED_AT", time.Now().String())
}

appSrc := p.dag.Host().Directory(".", dagger.HostDirectoryOpts{
Include: []string{
"images",
"lib",
"styles",
"views",
"Gemfile",
"Gemfile.lock",
"LICENSE",
"README.md",
"Rakefile",
}})

p.workspace = p.workspace.
WithDirectory("/app", appSrc).
WithWorkdir("/app").
WithExec([]string{"bundle", "install", "--frozen"}).
WithExec([]string{"rake", "-T"}).
WithEntrypoint([]string{"/bin/bash"}).
WithDefaultArgs()

if p.debug {
_, err := p.workspace.Pipeline("export tmp/image.tar").
Export(p.ctx, "tmp/image.tar")
if err != nil {
panic(err)
}
}

return p.ok()
}

func (p *Pipeline) publish() *Pipeline {
ghcrUsername := os.Getenv("GHCR_USERNAME")
if ghcrUsername == "" {
fmt.Println("👮 Skip publishing")
fmt.Println("👮 GHCR_USERNAME env var is required")
return p
}
registryUsername := ghcrUsername

ghcrPassword := os.Getenv("GHCR_PASSWORD")
if ghcrPassword == "" {
fmt.Println("👮 Skip publishing")
fmt.Println("👮 GHCR_PASSWORD env var is required")
return p
}
registryPassword := p.dag.SetSecret("password", ghcrPassword)

gitSHA := os.Getenv("GITHUB_SHA")
if gitSHA == "" {
gitSHA = "dev"
}

imageURL := fmt.Sprintf("ghcr.io/%s/nightly:%s", ghcrUsername, gitSHA)

var err error
_, err = p.workspace.Pipeline(fmt.Sprintf("publish %s", imageURL)).
WithRegistryAuth("ghcr.io", registryUsername, registryPassword).
Publish(p.ctx, imageURL)
if err != nil {
panic(err)
}

fmt.Printf("\n✅ Published as https://%s\n", imageURL)

return p
}

type Versions struct {
toolVersions map[string]string
}

// https://www.ruby-lang.org/en/downloads/releases/ || asdf list all ruby
func (v *Versions) Ruby() string {
return v.toolVersions["ruby"]
}

func currentToolVersions() *Versions {
return &Versions{
toolVersions: toolVersions(),
}
}

func toolVersions() map[string]string {
wd, err := os.Getwd()
if err != nil {
panic(err)
}
versions, err := os.Open(filepath.Join(wd, ".tool-versions"))
if err != nil {
panic(err)
}
toolVersions := make(map[string]string)
scanner := bufio.NewScanner(versions)
for scanner.Scan() {
line := scanner.Text()
toolAndVersion := strings.Split(line, " ")
toolVersions[toolAndVersion[0]] = toolAndVersion[1]
}

return toolVersions
}

0 comments on commit caa10f4

Please sign in to comment.