Skip to content

Commit

Permalink
ZEA-4175: Handle the containerized mode of Node.js output directory (#…
Browse files Browse the repository at this point in the history
…376)

#### Description (required)

- **fix(planner/nodejs): Make build script determination reliable**
- **refactor(planner/gleam): Optimize serverless generation**
- **feat(planner/nodejs): Support containerized outputDir generation**
- **feat(planner/nodejs): Support containerized static**
- **feat(zbpack): Support new containerized static convention**
- **feat(planner/dart): Support containerized static**
- **fix(planner/nodejs): Do not fill start command if there is static
output directory**
- **test(transformer): Update for latest serverless + outputDir
convention**
- **test(e2e): Add vite vanilla test**
- **chore: Update dependencies**
- **ci: Use go-version-file for release**

Node.js and Flutter has been manually tested.

#### Related issues & labels (optional)

- Closes ZEA-4175
- Suggested label: enhancement, bug
  • Loading branch information
yuaanlin authored Nov 7, 2024
2 parents e6f3f03 + 1125f21 commit 3487729
Show file tree
Hide file tree
Showing 30 changed files with 261 additions and 118 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ permissions:

jobs:
goreleaser:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -19,7 +19,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.22
go-version-file: "go.mod"
- name: Run GoReleaser
uses: goreleaser/[email protected]
with:
Expand Down
35 changes: 16 additions & 19 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
module github.com/zeabur/zbpack

go 1.21.0
go 1.22.0

toolchain go1.21.6
toolchain go1.22.7

require (
github.com/spf13/afero v1.11.0
github.com/stretchr/testify v1.9.0
)

require (
github.com/containerd/typeurl/v2 v2.2.0 // indirect
github.com/containerd/typeurl/v2 v2.2.2 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/gkampitakis/ciinfo v0.3.0 // indirect
github.com/gkampitakis/go-diff v1.3.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
Expand All @@ -22,9 +22,8 @@ require (
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 // indirect
github.com/juju/loggo v1.0.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/juju/errors v1.0.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
Expand All @@ -33,11 +32,12 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/locafero v0.6.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
Expand All @@ -46,15 +46,12 @@ require (
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
github.com/ulikunitz/xz v0.5.11 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
golang.org/x/sys v0.26.0 // indirect
google.golang.org/protobuf v1.35.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Expand All @@ -66,11 +63,11 @@ require (
github.com/distribution/reference v0.6.0
github.com/evanw/esbuild v0.24.0
github.com/gkampitakis/go-snaps v0.5.7
github.com/goccy/go-yaml v1.12.0
github.com/goccy/go-yaml v1.13.5
github.com/google/go-github/v63 v63.0.0
github.com/google/uuid v1.6.0
github.com/iancoleman/strcase v0.3.0
github.com/moby/buildkit v0.16.0
github.com/moby/buildkit v0.17.0
github.com/moznion/go-optional v0.12.0
github.com/otiai10/copy v1.14.0
github.com/pan93412/envexpander/v3 v3.0.0
Expand All @@ -79,6 +76,6 @@ require (
github.com/spf13/cast v1.7.0
github.com/spf13/cobra v1.8.1
github.com/spf13/viper v1.19.0
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c
golang.org/x/text v0.19.0
)
101 changes: 42 additions & 59 deletions go.sum

Large diffs are not rendered by default.

16 changes: 14 additions & 2 deletions internal/dart/dart.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ func GenerateDockerfile(meta types.PlanMeta) (string, error) {
build := meta["build"]

if meta["framework"] == "flutter" {
return `FROM ubuntu:latest
dockerfile := `FROM ubuntu:latest
RUN apt-get update && apt-get install -y curl git unzip xz-utils zip libglu1-mesa
RUN git clone https://github.com/flutter/flutter.git /usr/local/flutter
ENV PATH="/usr/local/flutter/bin:/usr/local/flutter/bin/cache/dart-sdk/bin:${PATH}"
Expand All @@ -24,7 +24,19 @@ RUN flutter pub get
FROM scratch
COPY --from=0 /app/build/web /
`, nil
`

// We run it with caddy for Containerized mode.
if serverless, ok := meta["serverless"]; ok && serverless != "true" {
caddy := `
FROM zeabur/caddy-static AS runtime
COPY --from=1 / /usr/share/caddy
`

dockerfile += caddy
}

return dockerfile, nil
}

if meta["framework"] == "serverpod" {
Expand Down
38 changes: 38 additions & 0 deletions internal/dart/dart_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package dart_test

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/zeabur/zbpack/internal/dart"
)

func TestGenerateDockerfileStatic(t *testing.T) {
t.Parallel()

t.Run("flutter, serverless", func(t *testing.T) {
t.Parallel()

dockerfile, err := dart.GenerateDockerfile(map[string]string{
"framework": "flutter",
"serverless": "true",
})

assert.NoError(t, err)
assert.Contains(t, dockerfile, "FROM scratch")
assert.NotContains(t, dockerfile, "FROM zeabur/caddy-static")
})

t.Run("flutter, non-serverless", func(t *testing.T) {
t.Parallel()

dockerfile, err := dart.GenerateDockerfile(map[string]string{
"framework": "flutter",
"serverless": "false",
})

assert.NoError(t, err)
assert.Contains(t, dockerfile, "FROM scratch")
assert.Contains(t, dockerfile, "FROM zeabur/caddy-static")
})
}
2 changes: 1 addition & 1 deletion internal/dart/identify.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func (i *identify) PlanMeta(options plan.NewPlannerOptions) types.PlanMeta {

if od := determineOutputDir(ctx); od != "" {
meta["serverless"] = strconv.FormatBool(
utils.GetExplicitServerlessConfig(ctx.Config).TakeOr(false),
utils.GetExplicitServerlessConfig(ctx.Config).TakeOr(true),
)
meta["outputDir"] = od
}
Expand Down
28 changes: 12 additions & 16 deletions internal/gleam/gleam.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,30 @@ import (

// GenerateDockerfile generates the Dockerfile for Gleam projects.
func GenerateDockerfile(m types.PlanMeta) (string, error) {
if m["serverless"] == "true" {
return `FROM ghcr.io/gleam-lang/gleam:v1.3.2-erlang-alpine
dockerfile := `FROM ghcr.io/gleam-lang/gleam:v1.3.2-erlang-alpine
RUN apk add --no-cache elixir
RUN mix local.hex --force
RUN mix local.rebar --force
COPY . /build/
RUN cd /build \
&& gleam export erlang-shipment \
&& mv build/erlang-shipment /app \
&& rm -r /build
&& rm -r /build`

if m["serverless"] == "true" {
dockerfile += `
FROM scratch AS output
COPY --from=0 /app /
`, nil
}

return `FROM ghcr.io/gleam-lang/gleam:v1.3.2-erlang-alpine
RUN apk add --no-cache elixir
RUN mix local.hex --force
RUN mix local.rebar --force
COPY . /build/
RUN cd /build \
&& gleam export erlang-shipment \
&& mv build/erlang-shipment /app \
&& rm -r /build
`
} else {
dockerfile += `
WORKDIR /app
ENTRYPOINT ["/app/entrypoint.sh"]
CMD ["run"]`, nil
CMD ["run"]
`
}

return dockerfile, nil
}

type pack struct {
Expand Down
34 changes: 34 additions & 0 deletions internal/gleam/gleam_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package gleam_test

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/zeabur/zbpack/internal/gleam"
)

func TestGenerateDockerfile(t *testing.T) {
t.Parallel()

t.Run("serverless", func(t *testing.T) {
t.Parallel()

dockerfile, err := gleam.GenerateDockerfile(map[string]string{
"serverless": "true",
})

assert.NoError(t, err)
assert.Contains(t, dockerfile, "\nFROM scratch AS output")
})

t.Run("non-serverless", func(t *testing.T) {
t.Parallel()

dockerfile, err := gleam.GenerateDockerfile(map[string]string{
"serverless": "false",
})

assert.NoError(t, err)
assert.Contains(t, dockerfile, "\nWORKDIR /app")
})
}
8 changes: 8 additions & 0 deletions internal/nodejs/__snapshots__/template_test.snap
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ RUN yarn build
FROM scratch AS output
COPY --from=build /src///app/dist /

FROM zeabur/caddy-static AS runtime
COPY --from=output / /usr/share/caddy



---

Expand Down Expand Up @@ -176,6 +180,10 @@ RUN yarn install
FROM scratch AS output
COPY --from=build /src/myservice//app/dist /

FROM zeabur/caddy-static AS runtime
COPY --from=output / /usr/share/caddy



---

Expand Down
24 changes: 19 additions & 5 deletions internal/nodejs/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"log"
"path/filepath"
"slices"
"strconv"
"strings"

Expand Down Expand Up @@ -376,7 +377,13 @@ func GetBuildScript(ctx *nodePlanContext) string {
return bs.Unwrap()
}

scriptsOrderedKey := make([]string, 0, len(packageJSON.Scripts))
for key := range packageJSON.Scripts {
scriptsOrderedKey = append(scriptsOrderedKey, key)
}
slices.Sort(scriptsOrderedKey)

for _, key := range scriptsOrderedKey {
if strings.Contains(key, "build") {
*bs = optional.Some(key)
return bs.Unwrap()
Expand Down Expand Up @@ -730,6 +737,12 @@ func GetStartCmd(ctx *nodePlanContext) string {
return cmd.Unwrap()
}

// if the app is deployed as static files, we should not start the app.
if GetStaticOutputDir(ctx) != "" {
*cmd = optional.Some("")
return cmd.Unwrap()
}

if startCmd, err := plan.Cast(ctx.Config.Get(plan.ConfigStartCommand), cast.ToStringE).Take(); err == nil {
*cmd = optional.Some(startCmd)
return cmd.Unwrap()
Expand Down Expand Up @@ -998,17 +1011,18 @@ func GetMeta(opt GetMetaOptions) types.PlanMeta {
meta["serverless"] = strconv.FormatBool(serverless)
}

// only set outputDir if there is no custom start command (because if there is, it shouldn't be a static project)
if buildCmd == "" {
startCmd := GetStartCmd(ctx)
meta["startCmd"] = startCmd

// only set outputDir if there is no start command
// (because if there is, it shouldn't be a static project)
if startCmd == "" {
staticOutputDir := GetStaticOutputDir(ctx)
if staticOutputDir != "" {
meta["outputDir"] = staticOutputDir
return meta
}
}

startCmd := GetStartCmd(ctx)
meta["startCmd"] = startCmd

return meta
}
35 changes: 35 additions & 0 deletions internal/nodejs/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/gkampitakis/go-snaps/snaps"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zeabur/zbpack/internal/nodejs"
)

Expand Down Expand Up @@ -242,3 +243,37 @@ func TestTemplate_Bun(t *testing.T) {
assert.NoError(t, err)
snaps.MatchSnapshot(t, result)
}

func TestTemplate_ServerlessOutputDir(t *testing.T) {
t.Parallel()

t.Run("with serverless", func(t *testing.T) {
ctx := nodejs.TemplateContext{
NodeVersion: "18",
InstallCmd: "RUN yarn install",
Serverless: true,
OutputDir: "/app/dist",
}

result, err := ctx.Execute()
assert.NoError(t, err)

require.Contains(t, result, "FROM scratch AS output")
require.NotContains(t, result, "FROM zeabur/caddy-static AS runtime")
})

t.Run("without serverless", func(t *testing.T) {
ctx := nodejs.TemplateContext{
NodeVersion: "18",
InstallCmd: "RUN yarn install",
Serverless: false,
OutputDir: "/app/dist",
}

result, err := ctx.Execute()
assert.NoError(t, err)

require.Contains(t, result, "FROM scratch AS output")
require.Contains(t, result, "FROM zeabur/caddy-static AS runtime")
})
}
Loading

0 comments on commit 3487729

Please sign in to comment.