FS: Call IndexDataHooks for custom version string (#112670)
* Add enterprise hooks * wip... * undo * update wire gen * remove old hook thing * move build info into seperate func * align fs context middleware with grafana, setting SignedInUser * Call IndexDataHooks to get modified build info * update tests * go workspace * idk, reset workspace files or whatever * conditionally mount license * support loading decoupled plugins from cdn --------- Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
This commit is contained in:
co-authored by
Ashley Harrison
parent
71d10a3fa3
commit
bb6d7d02c7
@@ -44,7 +44,14 @@ local_resource(
|
||||
)
|
||||
|
||||
# --- Docker Compose
|
||||
docker_compose("./docker-compose.yaml")
|
||||
# define service overrides needed for running with enterprise
|
||||
# this mounts the dev license into the grafana-api service
|
||||
base_config = read_yaml('./docker-compose.yaml')
|
||||
base_volumes = base_config['services']['grafana-api']['volumes']
|
||||
enterprise_overrides = {'services':{'grafana-api': {'volumes': base_volumes + ['../../data/license.jwt:/grafana/data/license.jwt'] }}}
|
||||
|
||||
# check if license exists and apply enterprise overrides if so
|
||||
docker_compose(["./docker-compose.yaml", encode_yaml(enterprise_overrides)]) if os.path.exists("../../data/license.jwt") else docker_compose("./docker-compose.yaml")
|
||||
dc_resource("proxy",
|
||||
resource_deps=["grafana-api", "frontend-service"],
|
||||
labels=["services"]
|
||||
@@ -66,7 +73,7 @@ dc_resource("postgres", labels=["misc"])
|
||||
dc_resource("tempo-init", labels=["misc"])
|
||||
|
||||
# paths in tilt files are confusing....
|
||||
# - if tilt is dealing the the path, it is relative to the Tiltfile
|
||||
# - if tilt is dealing with the path, it is relative to the Tiltfile
|
||||
# - if docker is dealing with the path, it is relative to the context
|
||||
docker_build('grafana-fs-dev',
|
||||
# Set the docker context to the root of the repo
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd ../../
|
||||
|
||||
echo "Go mod cache: $(go env GOMODCACHE), $(ls -1 $(go env GOMODCACHE) | wc -l) items"
|
||||
echo "Go build cache: $(go env GOCACHE), $(ls -1 $(go env GOCACHE) | wc -l) items"
|
||||
# Support running this file from tilt (where the cwd is devenv/frontend-service), or directly from the root
|
||||
if [[ -f build-grafana.sh ]]; then
|
||||
cd ../../
|
||||
fi
|
||||
|
||||
# The docker container, even on macOS, is linux, so we need to cross-compile
|
||||
# on macOS hosts to work on linux.
|
||||
@@ -17,7 +17,16 @@ fi
|
||||
# Need to build version into the binary so plugin compatibility works correctly
|
||||
VERSION=$(jq -r .version package.json)
|
||||
|
||||
# Build enterprise if it is linked in
|
||||
EXTRA_TAGS=""
|
||||
if [[ -f pkg/extensions/ext.go ]]; then
|
||||
EXTRA_TAGS="-tags enterprise"
|
||||
fi
|
||||
|
||||
# EXTRA_TAGS is intentionally unquoted to build the command
|
||||
# shellcheck disable=SC2086
|
||||
go build -v \
|
||||
-ldflags "-X main.version=${VERSION}" \
|
||||
-gcflags "all=-N -l" \
|
||||
${EXTRA_TAGS} \
|
||||
-o ./devenv/frontend-service/build/grafana ./pkg/cmd/grafana
|
||||
|
||||
@@ -8,6 +8,7 @@ services:
|
||||
dockerfile: proxy.dockerfile
|
||||
volumes:
|
||||
- ../../public/build:/cdn/public/build
|
||||
- ../../public/app/plugins:/cdn/public/app/plugins
|
||||
- ../../public/fonts:/cdn/public/fonts
|
||||
ports:
|
||||
- '3000:80' # Gateway
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/authz"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/frontend"
|
||||
"github.com/grafana/grafana/pkg/services/hooks"
|
||||
"github.com/grafana/grafana/pkg/services/licensing"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||
@@ -46,8 +47,9 @@ func NewModule(opts Options,
|
||||
license licensing.Licensing,
|
||||
moduleRegisterer ModuleRegisterer,
|
||||
storageBackend resource.StorageBackend, // Ensures unified storage backend is initialized
|
||||
hooksService *hooks.HooksService,
|
||||
) (*ModuleServer, error) {
|
||||
s, err := newModuleServer(opts, apiOpts, features, cfg, storageMetrics, indexMetrics, reg, promGatherer, license, moduleRegisterer, storageBackend)
|
||||
s, err := newModuleServer(opts, apiOpts, features, cfg, storageMetrics, indexMetrics, reg, promGatherer, license, moduleRegisterer, storageBackend, hooksService)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -70,6 +72,7 @@ func newModuleServer(opts Options,
|
||||
license licensing.Licensing,
|
||||
moduleRegisterer ModuleRegisterer,
|
||||
storageBackend resource.StorageBackend,
|
||||
hooksService *hooks.HooksService,
|
||||
) (*ModuleServer, error) {
|
||||
rootCtx, shutdownFn := context.WithCancel(context.Background())
|
||||
|
||||
@@ -93,6 +96,7 @@ func newModuleServer(opts Options,
|
||||
license: license,
|
||||
moduleRegisterer: moduleRegisterer,
|
||||
storageBackend: storageBackend,
|
||||
hooksService: hooksService,
|
||||
}
|
||||
|
||||
return s, nil
|
||||
@@ -134,6 +138,7 @@ type ModuleServer struct {
|
||||
|
||||
// moduleRegisterer allows registration of modules provided by other builds (e.g. enterprise).
|
||||
moduleRegisterer ModuleRegisterer
|
||||
hooksService *hooks.HooksService
|
||||
}
|
||||
|
||||
// init initializes the server and its services.
|
||||
@@ -205,7 +210,7 @@ func (s *ModuleServer) Run() error {
|
||||
})
|
||||
|
||||
m.RegisterModule(modules.FrontendServer, func() (services.Service, error) {
|
||||
return frontend.ProvideFrontendService(s.cfg, s.features, s.promGatherer, s.registerer, s.license)
|
||||
return frontend.ProvideFrontendService(s.cfg, s.features, s.promGatherer, s.registerer, s.license, s.hooksService)
|
||||
})
|
||||
|
||||
m.RegisterModule(modules.OperatorServer, s.initOperatorServer)
|
||||
|
||||
@@ -27,6 +27,8 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/modules"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/hooks"
|
||||
"github.com/grafana/grafana/pkg/services/licensing"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/sqlutil"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||
@@ -330,8 +332,10 @@ func initModuleServerForTest(
|
||||
apiOpts api.ServerOptions,
|
||||
) testModuleServer {
|
||||
tracer := tracing.InitializeTracerForTest()
|
||||
hooksService := hooks.ProvideService()
|
||||
license := &licensing.OSSLicensingService{}
|
||||
|
||||
ms, err := NewModule(opts, apiOpts, featuremgmt.WithFeatures(featuremgmt.FlagUnifiedStorageSearch), cfg, nil, nil, prometheus.NewRegistry(), prometheus.DefaultGatherer, tracer, nil, ProvideNoopModuleRegisterer(), nil)
|
||||
ms, err := NewModule(opts, apiOpts, featuremgmt.WithFeatures(featuremgmt.FlagUnifiedStorageSearch), cfg, nil, nil, prometheus.NewRegistry(), prometheus.DefaultGatherer, tracer, license, ProvideNoopModuleRegisterer(), nil, hooksService)
|
||||
require.NoError(t, err)
|
||||
|
||||
conn, err := grpc.NewClient(cfg.GRPCServer.Address,
|
||||
|
||||
@@ -1644,7 +1644,7 @@ func InitializeModuleServer(cfg *setting.Cfg, opts Options, apiOpts api.ServerOp
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
moduleServer, err := NewModule(opts, apiOpts, featureToggles, cfg, storageMetrics, bleveIndexMetrics, registerer, gatherer, tracingService, ossLicensingService, moduleRegisterer, storageBackend)
|
||||
moduleServer, err := NewModule(opts, apiOpts, featureToggles, cfg, storageMetrics, bleveIndexMetrics, registerer, gatherer, tracingService, ossLicensingService, moduleRegisterer, storageBackend, hooksService)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -6,8 +6,12 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/contexthandler/ctxkey"
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
)
|
||||
|
||||
@@ -18,24 +22,38 @@ func (s *frontendService) contextMiddleware() web.Middleware {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
reqContext := &contextmodel.ReqContext{
|
||||
Context: web.FromContext(ctx),
|
||||
Logger: log.New("context"),
|
||||
}
|
||||
span := trace.SpanFromContext(ctx)
|
||||
ctx = setRequestContext(ctx)
|
||||
|
||||
// inject ReqContext in the context
|
||||
ctx = context.WithValue(ctx, ctxkey.Key{}, reqContext)
|
||||
|
||||
// Set the context for the http.Request.Context
|
||||
// This modifies both r and reqContext.Req since they point to the same value
|
||||
*reqContext.Req = *reqContext.Req.WithContext(ctx)
|
||||
|
||||
traceID := tracing.TraceIDFromContext(ctx, false)
|
||||
if traceID != "" {
|
||||
reqContext.Logger = reqContext.Logger.New("traceID", traceID)
|
||||
}
|
||||
// Preserve the original span so the setRequestContext span doesn't get propagated as a parent of the rest of the request
|
||||
ctx = trace.ContextWithSpan(ctx, span)
|
||||
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func setRequestContext(ctx context.Context) context.Context {
|
||||
ctx, span := tracing.Start(ctx, "setRequestContext")
|
||||
defer span.End()
|
||||
|
||||
reqContext := &contextmodel.ReqContext{
|
||||
Context: web.FromContext(ctx),
|
||||
Logger: log.New("context"),
|
||||
SignedInUser: &user.SignedInUser{},
|
||||
}
|
||||
|
||||
// inject ReqContext in the context
|
||||
ctx = context.WithValue(ctx, ctxkey.Key{}, reqContext)
|
||||
|
||||
// Set the context for the http.Request.Context
|
||||
// This modifies both r and reqContext.Req since they point to the same value
|
||||
*reqContext.Req = *reqContext.Req.WithContext(ctx)
|
||||
|
||||
traceID := tracing.TraceIDFromContext(ctx, false)
|
||||
if traceID != "" {
|
||||
reqContext.Logger = reqContext.Logger.New("traceID", traceID)
|
||||
}
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/middleware/requestmeta"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
fswebassets "github.com/grafana/grafana/pkg/services/frontend/webassets"
|
||||
"github.com/grafana/grafana/pkg/services/hooks"
|
||||
"github.com/grafana/grafana/pkg/services/licensing"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
@@ -50,13 +51,13 @@ type frontendService struct {
|
||||
index *IndexProvider
|
||||
}
|
||||
|
||||
func ProvideFrontendService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, promGatherer prometheus.Gatherer, promRegister prometheus.Registerer, license licensing.Licensing) (*frontendService, error) {
|
||||
func ProvideFrontendService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, promGatherer prometheus.Gatherer, promRegister prometheus.Registerer, license licensing.Licensing, hooksService *hooks.HooksService) (*frontendService, error) {
|
||||
assetsManifest, err := fswebassets.GetWebAssets(cfg, license)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
index, err := NewIndexProvider(cfg, assetsManifest)
|
||||
index, err := NewIndexProvider(cfg, assetsManifest, license, hooksService)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -11,8 +11,11 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/services/contexthandler"
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/hooks"
|
||||
"github.com/grafana/grafana/pkg/services/licensing"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
@@ -24,6 +27,7 @@ func createTestService(t *testing.T, cfg *setting.Cfg) *frontendService {
|
||||
|
||||
features := featuremgmt.WithFeatures()
|
||||
license := &licensing.OSSLicensingService{}
|
||||
hooksService := hooks.ProvideService()
|
||||
|
||||
var promRegister prometheus.Registerer = prometheus.NewRegistry()
|
||||
promGatherer := promRegister.(*prometheus.Registry)
|
||||
@@ -32,7 +36,7 @@ func createTestService(t *testing.T, cfg *setting.Cfg) *frontendService {
|
||||
cfg.BuildVersion = "10.3.0"
|
||||
}
|
||||
|
||||
service, err := ProvideFrontendService(cfg, features, promGatherer, promRegister, license)
|
||||
service, err := ProvideFrontendService(cfg, features, promGatherer, promRegister, license, hooksService)
|
||||
require.NoError(t, err)
|
||||
|
||||
return service
|
||||
@@ -182,3 +186,56 @@ func TestFrontendService_Middleware(t *testing.T) {
|
||||
mux.ServeHTTP(recorder, req)
|
||||
})
|
||||
}
|
||||
|
||||
func TestFrontendService_IndexHooks(t *testing.T) {
|
||||
publicDir := setupTestWebAssets(t)
|
||||
cfg := &setting.Cfg{
|
||||
HTTPPort: "3000",
|
||||
StaticRootPath: publicDir,
|
||||
BuildVersion: "10.3.0",
|
||||
}
|
||||
|
||||
t.Run("should handle hooks that modify buildInfo fields", func(t *testing.T) {
|
||||
service := createTestService(t, cfg)
|
||||
|
||||
// Add a hook that modifies various buildInfo fields
|
||||
service.index.hooksService.AddIndexDataHook(func(indexData *dtos.IndexViewData, req *contextmodel.ReqContext) {
|
||||
indexData.Settings.BuildInfo.Version = "99.99.99"
|
||||
indexData.Settings.BuildInfo.VersionString = "Custom Edition v99.99.99 (custom)"
|
||||
indexData.Settings.BuildInfo.Edition = "custom-edition"
|
||||
})
|
||||
|
||||
mux := web.New()
|
||||
service.addMiddlewares(mux)
|
||||
service.registerRoutes(mux)
|
||||
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
recorder := httptest.NewRecorder()
|
||||
mux.ServeHTTP(recorder, req)
|
||||
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
body := recorder.Body.String()
|
||||
assert.Contains(t, body, "99.99.99", "Hook should have modified the version")
|
||||
assert.Contains(t, body, "Custom Edition v99.99.99 (custom)", "Hook should have modified the version string")
|
||||
assert.Contains(t, body, "custom-edition", "Hook should have modified the edition")
|
||||
})
|
||||
|
||||
t.Run("should work without any hooks registered", func(t *testing.T) {
|
||||
service := createTestService(t, cfg)
|
||||
|
||||
mux := web.New()
|
||||
service.addMiddlewares(mux)
|
||||
service.registerRoutes(mux)
|
||||
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
recorder := httptest.NewRecorder()
|
||||
mux.ServeHTTP(recorder, req)
|
||||
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
body := recorder.Body.String()
|
||||
assert.Contains(t, body, "<div id=\"reactRoot\"></div>")
|
||||
// The build version comes from setting.BuildVersion (global), not cfg.BuildVersion
|
||||
// So we just check that the page renders successfully
|
||||
assert.Contains(t, body, "window.grafanaBootData")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package frontend
|
||||
|
||||
import "github.com/grafana/grafana/pkg/setting"
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
// This is a copy of dtos.FrontendSettingsDTO with only the fields that the frontend-service
|
||||
// sends, to prevent default values from overriding what comes from the /bootdata call.
|
||||
@@ -20,6 +23,8 @@ type FSFrontendSettings struct {
|
||||
PasswordHint string `json:"passwordHint,omitempty"`
|
||||
AnonymousEnabled bool `json:"anonymousEnabled,omitempty"`
|
||||
|
||||
BuildInfo dtos.FrontendSettingsBuildInfoDTO `json:"buildInfo"`
|
||||
|
||||
GoogleAnalyticsId string `json:"googleAnalyticsId,omitempty"`
|
||||
GoogleAnalytics4Id string `json:"googleAnalytics4Id,omitempty"`
|
||||
GoogleAnalytics4SendManualPageViews bool `json:"GoogleAnalytics4SendManualPageViews,omitempty"`
|
||||
|
||||
@@ -12,13 +12,18 @@ import (
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
"github.com/grafana/grafana/pkg/services/contexthandler"
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
"github.com/grafana/grafana/pkg/services/hooks"
|
||||
"github.com/grafana/grafana/pkg/services/licensing"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
type IndexProvider struct {
|
||||
log logging.Logger
|
||||
index *template.Template
|
||||
data IndexViewData
|
||||
log logging.Logger
|
||||
index *template.Template
|
||||
data IndexViewData
|
||||
hooksService *hooks.HooksService
|
||||
}
|
||||
|
||||
type IndexViewData struct {
|
||||
@@ -51,12 +56,14 @@ var (
|
||||
htmlTemplates = template.Must(template.New("html").Delims("[[", "]]").ParseFS(templatesFS, `*.html`))
|
||||
)
|
||||
|
||||
func NewIndexProvider(cfg *setting.Cfg, assetsManifest dtos.EntryPointAssets) (*IndexProvider, error) {
|
||||
func NewIndexProvider(cfg *setting.Cfg, assetsManifest dtos.EntryPointAssets, license licensing.Licensing, hooksService *hooks.HooksService) (*IndexProvider, error) {
|
||||
t := htmlTemplates.Lookup("index.html")
|
||||
if t == nil {
|
||||
return nil, fmt.Errorf("missing index template")
|
||||
}
|
||||
|
||||
logger := logging.DefaultLogger.With("logger", "index-provider")
|
||||
|
||||
// subset of frontend settings needed for the login page
|
||||
// TODO what about enterprise settings here?
|
||||
frontendSettings := FSFrontendSettings{
|
||||
@@ -87,13 +94,13 @@ func NewIndexProvider(cfg *setting.Cfg, assetsManifest dtos.EntryPointAssets) (*
|
||||
RudderstackWriteKey: cfg.RudderstackWriteKey,
|
||||
TrustedTypesDefaultPolicyEnabled: (cfg.CSPEnabled && strings.Contains(cfg.CSPTemplate, "require-trusted-types-for")) || (cfg.CSPReportOnlyEnabled && strings.Contains(cfg.CSPReportOnlyTemplate, "require-trusted-types-for")),
|
||||
VerifyEmailEnabled: cfg.VerifyEmailEnabled,
|
||||
BuildInfo: getBuildInfo(license, cfg),
|
||||
}
|
||||
|
||||
defaultUser := dtos.CurrentUser{}
|
||||
|
||||
return &IndexProvider{
|
||||
log: logging.DefaultLogger.With("logger", "index-provider"),
|
||||
index: t,
|
||||
log: logger,
|
||||
index: t,
|
||||
hooksService: hooksService,
|
||||
data: IndexViewData{
|
||||
AppTitle: "Grafana",
|
||||
AppSubUrl: cfg.AppSubURL, // Based on the request?
|
||||
@@ -109,13 +116,13 @@ func NewIndexProvider(cfg *setting.Cfg, assetsManifest dtos.EntryPointAssets) (*
|
||||
|
||||
Assets: assetsManifest,
|
||||
Settings: frontendSettings,
|
||||
DefaultUser: defaultUser,
|
||||
DefaultUser: dtos.CurrentUser{},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *IndexProvider) HandleRequest(writer http.ResponseWriter, request *http.Request) {
|
||||
_, span := tracer.Start(request.Context(), "frontend.index.HandleRequest")
|
||||
ctx, span := tracer.Start(request.Context(), "frontend.index.HandleRequest")
|
||||
defer span.End()
|
||||
|
||||
if request.Method != "GET" {
|
||||
@@ -142,6 +149,9 @@ func (p *IndexProvider) HandleRequest(writer http.ResponseWriter, request *http.
|
||||
writer.Header().Set("Content-Security-Policy-Report-Only", policy)
|
||||
}
|
||||
|
||||
reqCtx := contexthandler.FromContext(ctx)
|
||||
p.runIndexDataHooks(reqCtx, &data)
|
||||
|
||||
writer.Header().Set("Content-Type", "text/html; charset=UTF-8")
|
||||
writer.WriteHeader(200)
|
||||
if err := p.index.Execute(writer, &data); err != nil {
|
||||
@@ -151,3 +161,43 @@ func (p *IndexProvider) HandleRequest(writer http.ResponseWriter, request *http.
|
||||
panic(fmt.Sprintf("Error rendering index\n %s", err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *IndexProvider) runIndexDataHooks(reqCtx *contextmodel.ReqContext, data *IndexViewData) {
|
||||
// Create a dummy struct to pass to the hooks, and then extract the data back out from it
|
||||
legacyIndexViewData := dtos.IndexViewData{
|
||||
Settings: &dtos.FrontendSettingsDTO{
|
||||
BuildInfo: data.Settings.BuildInfo,
|
||||
},
|
||||
}
|
||||
|
||||
p.hooksService.RunIndexDataHooks(&legacyIndexViewData, reqCtx)
|
||||
|
||||
data.Settings.BuildInfo = legacyIndexViewData.Settings.BuildInfo
|
||||
}
|
||||
|
||||
func getBuildInfo(license licensing.Licensing, cfg *setting.Cfg) dtos.FrontendSettingsBuildInfoDTO {
|
||||
version := setting.BuildVersion
|
||||
commit := setting.BuildCommit
|
||||
commitShort := getShortCommitHash(setting.BuildCommit, 10)
|
||||
buildstamp := setting.BuildStamp
|
||||
versionString := fmt.Sprintf(`%s v%s (%s)`, setting.ApplicationName, version, commitShort)
|
||||
|
||||
buildInfo := dtos.FrontendSettingsBuildInfoDTO{
|
||||
Version: version,
|
||||
VersionString: versionString,
|
||||
Commit: commit,
|
||||
CommitShort: commitShort,
|
||||
Buildstamp: buildstamp,
|
||||
Edition: license.Edition(),
|
||||
Env: cfg.Env,
|
||||
}
|
||||
|
||||
return buildInfo
|
||||
}
|
||||
|
||||
func getShortCommitHash(commitHash string, maxLength int) string {
|
||||
if len(commitHash) > maxLength {
|
||||
return commitHash[:maxLength]
|
||||
}
|
||||
return commitHash
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user