Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/manual-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ jobs:
goreleaser:
needs: validate-inputs
runs-on: ubuntu-latest
timeout-minutes: 90
steps:
- name: Check out code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ jobs:
# Build release binaries
goreleaser:
runs-on: ubuntu-latest
timeout-minutes: 90
steps:
- name: Check out code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Expand Down
43 changes: 43 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,45 @@ builds:
- goos: windows
goarch: arm
goarm: "7"
- id: dagu-headless
dir: ./cmd
binary: dagu
flags:
- -tags=headless
env:
- CGO_ENABLED=0
goos:
- linux
- darwin
- windows
goarch:
- "amd64"
- "386"
- "arm"
- "arm64"
- "ppc64le"
- "s390x"
goarm:
- "6"
- "7"
ignore:
# Go does not support windows/arm.
- goos: windows
goarch: arm
goarm: "6"
- goos: windows
goarch: arm
goarm: "7"

archives:
- id: dagu
ids:
- dagu
name_template: "dagu_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}"
- id: dagu-headless
ids:
- dagu-headless
name_template: "dagu-headless_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}"

release:
mode: keep-existing
Expand All @@ -53,6 +92,8 @@ changelog:

brews:
- skip_upload: auto
ids:
- dagu
repository:
owner: dagu-org
name: homebrew-brew
Expand All @@ -71,6 +112,8 @@ brews:

# Deprecated brew tap:
- skip_upload: auto
ids:
- dagu
repository:
owner: yohamta
name: homebrew-tap
Expand Down
36 changes: 36 additions & 0 deletions internal/service/frontend/assets_default_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (C) 2026 Yota Hamada
// SPDX-License-Identifier: GPL-3.0-or-later

//go:build !headless

package frontend_test

import (
"context"
"net/http"
"net/http/httptest"
"testing"

"github.com/go-chi/chi/v5"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/dagucloud/dagu/internal/cmn/config"
"github.com/dagucloud/dagu/internal/service/frontend"
)

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

require.True(t, frontend.WebUIEmbeddedForTest())

srv := frontend.NewRouteTestServerForTest(&config.Config{})
r := chi.NewMux()

require.NoError(t, frontend.SetupRoutesForTest(context.Background(), srv, r))

rec := httptest.NewRecorder()
r.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/", nil))

assert.Equal(t, http.StatusOK, rec.Code)
}
13 changes: 13 additions & 0 deletions internal/service/frontend/assets_embed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (C) 2026 Yota Hamada
// SPDX-License-Identifier: GPL-3.0-or-later

//go:build !headless

package frontend

import "embed"

//go:embed templates/* assets/*
var assetsFS embed.FS

const webUIEmbedded = true
12 changes: 12 additions & 0 deletions internal/service/frontend/assets_headless.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (C) 2026 Yota Hamada
// SPDX-License-Identifier: GPL-3.0-or-later

//go:build headless

package frontend

import "embed"

var assetsFS embed.FS

const webUIEmbedded = false
36 changes: 36 additions & 0 deletions internal/service/frontend/assets_headless_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (C) 2026 Yota Hamada
// SPDX-License-Identifier: GPL-3.0-or-later

//go:build headless

package frontend_test

import (
"context"
"net/http"
"net/http/httptest"
"testing"

"github.com/go-chi/chi/v5"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/dagucloud/dagu/internal/cmn/config"
"github.com/dagucloud/dagu/internal/service/frontend"
)

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

require.False(t, frontend.WebUIEmbeddedForTest())

srv := frontend.NewRouteTestServerForTest(&config.Config{})
r := chi.NewMux()

require.NoError(t, frontend.SetupRoutesForTest(context.Background(), srv, r))

rec := httptest.NewRecorder()
r.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/assets/bundle.js", nil))

assert.Equal(t, http.StatusNotFound, rec.Code)
}
29 changes: 29 additions & 0 deletions internal/service/frontend/export_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (C) 2026 Yota Hamada
// SPDX-License-Identifier: GPL-3.0-or-later

package frontend

import (
"context"

"github.com/go-chi/chi/v5"

"github.com/dagucloud/dagu/internal/cmn/config"
)

func WebUIEmbeddedForTest() bool {
return webUIEmbedded
}

func NewRouteTestServerForTest(cfg *config.Config) *Server {
return &Server{
config: cfg,
funcsConfig: funcsConfig{
BasePath: cfg.Server.BasePath,
},
}
}

func SetupRoutesForTest(ctx context.Context, srv *Server, r *chi.Mux) error {
return srv.setupRoutes(ctx, r)
}
2 changes: 1 addition & 1 deletion internal/service/frontend/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1036,7 +1036,7 @@ func ensureLeadingSlash(p string) string {
}

func (srv *Server) setupRoutes(ctx context.Context, r *chi.Mux) error {
if srv.config.Server.Headless {
if !srv.webUIEnabled() {
logger.Info(ctx, "Headless mode enabled: UI is disabled, but API remains active")
return nil
}
Expand Down
10 changes: 5 additions & 5 deletions internal/service/frontend/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"bytes"
"context"
"crypto/sha256"
"embed"
"encoding/hex"
"encoding/json"
"io"
Expand All @@ -28,9 +27,6 @@ import (
workspacepkg "github.com/dagucloud/dagu/internal/workspace"
)

//go:embed templates/* assets/*
var assetsFS embed.FS

const (
templatePath = "templates/"
baseTemplateName = "base"
Expand Down Expand Up @@ -65,8 +61,12 @@ func currentAssetVersion() string {
return assetVersion
}

func (srv *Server) webUIEnabled() bool {
return webUIEmbedded && !srv.config.Server.Headless
}

func (srv *Server) useTemplate(ctx context.Context, layout, name string) func(http.ResponseWriter, any) {
if srv.config.Server.Headless {
if !srv.webUIEnabled() {
return func(w http.ResponseWriter, _ any) {
http.Error(w, "Web UI is disabled in headless mode", http.StatusForbidden)
}
Expand Down
Loading