Skip to content

Commit

Permalink
improvement(dashboard): better warning logs (#5538)
Browse files Browse the repository at this point in the history
This commit adds a message about the dashboard to all Garden commands.
Previously we only showed it for the 'dev' command.

The message can be disabled.

It also consistently logs a warning if a user is logged in across all
cloud distros.
  • Loading branch information
eysi09 authored Dec 12, 2023
1 parent 2a81806 commit c1d2007
Show file tree
Hide file tree
Showing 11 changed files with 142 additions and 62 deletions.
34 changes: 19 additions & 15 deletions core/src/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,18 @@ import {
checkRequirements,
renderCommandErrors,
cliStyles,
getDashboardInfoMsg,
} from "./helpers.js"
import type { ParameterObject, GlobalOptions, ParameterValues } from "./params.js"
import { globalOptions, OUTPUT_RENDERERS } from "./params.js"
import type { ProjectConfig } from "../config/project.js"
import { ERROR_LOG_FILENAME, DEFAULT_GARDEN_DIR_NAME, LOGS_DIR_NAME, gardenEnv } from "../constants.js"
import {
ERROR_LOG_FILENAME,
DEFAULT_GARDEN_DIR_NAME,
LOGS_DIR_NAME,
gardenEnv,
DEFAULT_GARDEN_CLOUD_DOMAIN,
} from "../constants.js"
import { generateBasicDebugInfoReport } from "../commands/get/get-debug-info.js"
import type { AnalyticsHandler } from "../analytics/analytics.js"
import type { GardenPluginReference } from "../plugin/plugin.js"
Expand Down Expand Up @@ -244,13 +251,10 @@ ${renderCommands(commands)}
!command.noProject && command.getFullName() !== "dev" && command.getFullName() !== "serve"
? log.createLog({ name: "garden", showDuration: true })
: null
gardenInitLog?.info("Initializing...")

// Init Cloud API (if applicable)
let cloudApi: CloudApi | undefined

if (gardenInitLog) {
gardenInitLog.info("Initializing...")
}
if (!command.noProject) {
const config = await this.getProjectConfig(log, workingDir)
const cloudDomain = getGardenCloudDomain(config?.domain)
Expand Down Expand Up @@ -319,6 +323,16 @@ ${renderCommands(commands)}
garden = await makeDummyGarden(workingDir, contextOpts)
} else {
garden = await wrapActiveSpan("initializeGarden", () => this.getGarden(workingDir, contextOpts))
const isLoggedIn = !!cloudApi
const isCommunityEdition = garden.cloudDomain === DEFAULT_GARDEN_CLOUD_DOMAIN

if (!isLoggedIn && isCommunityEdition) {
await garden.emitWarning({
key: "web-app",
log,
message: "\n" + getDashboardInfoMsg(),
})
}

if (!gardenEnv.GARDEN_DISABLE_VERSION_CHECK) {
await garden.emitWarning({
Expand All @@ -333,16 +347,6 @@ ${renderCommands(commands)}

gardenLog.info(`Running in environment ${styles.highlight(`${garden.environmentName}.${garden.namespace}`)}`)

if (!cloudApi && garden.projectId) {
log.info("")
log.warn(
`Warning: You are not logged in into Garden Cloud. Please log in via the ${styles.command(
"garden login"
)} command.`
)
log.info("")
}

if (processRecord) {
// Update the db record for the process
await globalConfigStore.update("activeProcesses", String(processRecord.pid), {
Expand Down
12 changes: 11 additions & 1 deletion core/src/cli/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { globalDisplayOptions } from "./params.js"
import { GardenError, ParameterError, RuntimeError, toGardenError } from "../exceptions.js"
import { getPackageVersion, removeSlice } from "../util/util.js"
import type { Log } from "../logger/log-entry.js"
import { STATIC_DIR, gardenEnv, ERROR_LOG_FILENAME } from "../constants.js"
import { STATIC_DIR, gardenEnv, ERROR_LOG_FILENAME, DOCS_BASE_URL } from "../constants.js"
import { printWarningMessage } from "../logger/util.js"
import type { GlobalConfigStore } from "../config-store/global.js"
import { got } from "../util/http.js"
Expand Down Expand Up @@ -563,3 +563,13 @@ export function renderCommandErrors(logger: Logger, errors: Error[], log?: Log)
errorLog.info(`\nSee .garden/${ERROR_LOG_FILENAME} for detailed error message`)
}
}

export function getDashboardInfoMsg() {
return styles.success(deline`
🌿 Log in with ${styles.command(
"garden login"
)} to explore logs, past commands, and your dependency graph in the Garden dashboard.
Learn more at: ${styles.underline(`${DOCS_BASE_URL}/using-garden/dashboard`)}\n
`)
}
14 changes: 7 additions & 7 deletions core/src/commands/serve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import type { Garden } from "../garden.js"
import type { GardenPluginReference } from "../plugin/plugin.js"
import { CommandError, ParameterError, isEAddrInUseException, isErrnoException } from "../exceptions.js"
import { styles } from "../logger/styles.js"
import { getDashboardInfoMsg } from "../cli/helpers.js"
import { DEFAULT_GARDEN_CLOUD_DOMAIN } from "../constants.js"

export const defaultServerPort = 9777

Expand Down Expand Up @@ -156,16 +158,14 @@ export class ServeCommand<

try {
const cloudApi = await manager.getCloudApi({ log, cloudDomain, globalConfigStore: garden.globalConfigStore })
const isLoggedIn = !!cloudApi
const isCommunityEdition = cloudDomain === DEFAULT_GARDEN_CLOUD_DOMAIN

if (!cloudApi) {
if (!isLoggedIn && isCommunityEdition) {
await garden.emitWarning({
key: "web-app",
log,
message: styles.success(
`🌿 Explore logs, past commands, and your dependency graph in the Garden dashboard. Log in with ${styles.command(
"garden login"
)}.`
),
message: getDashboardInfoMsg(),
})
}

Expand All @@ -192,7 +192,7 @@ export class ServeCommand<
if (session?.shortId) {
const distroName = getCloudDistributionName(cloudDomain)
const livePageUrl = cloudApi.getLivePageUrl({ shortId: session.shortId }).toString()
const msg = dedent`${printEmoji("🌸", log)}Connected to ${distroName} ${printEmoji("🌸", log)}
const msg = dedent`\n${printEmoji("🌸", log)}Connected to ${distroName} ${printEmoji("🌸", log)}
Follow the link below to stream logs, run commands, and more from the Garden dashboard ${printEmoji(
"👇",
log
Expand Down
26 changes: 15 additions & 11 deletions core/src/garden.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ import {
SUPPORTED_ARCHITECTURES,
GardenApiVersion,
DOCS_BASE_URL,
DEFAULT_GARDEN_CLOUD_DOMAIN,
} from "./constants.js"
import type { Log } from "./logger/log-entry.js"
import { EventBus } from "./events/events.js"
Expand Down Expand Up @@ -186,7 +187,7 @@ export interface GardenOpts {
*/
gardenInitLog?: Log
monitors?: MonitorManager
noEnterprise?: boolean
skipCloudConnect?: boolean
persistent?: boolean
plugins?: RegisterPluginParam[]
sessionId?: string
Expand Down Expand Up @@ -562,7 +563,7 @@ export class Garden {

if (!existing || !existing.hidden) {
this.emittedWarnings.add(key)
log.warn(message + `\n→ Run ${styles.underline(`garden util hide-warning ${key}`)} to disable this warning.`)
log.warn(message + `\n→ Run ${styles.underline(`garden util hide-warning ${key}`)} to disable this message.`)
}
})
}
Expand Down Expand Up @@ -1868,18 +1869,17 @@ export const resolveGardenParams = profileAsync(async function _resolveGardenPar
const projectApiVersion = config.apiVersion
const sessionId = opts.sessionId || uuidv4()
const cloudApi = opts.cloudApi || null
const isCommunityEdition = !config.domain
const distroName = getCloudDistributionName(cloudApi?.domain || DEFAULT_GARDEN_CLOUD_DOMAIN)
const debugLevelCommands = ["dev", "serve", "exit", "quit"]
const cloudLogLevel = debugLevelCommands.includes(opts.commandInfo.name) ? LogLevel.debug : undefined
const cloudLog = log.createLog({ name: getCloudLogSectionName(distroName), fixLevel: cloudLogLevel })

let secrets: StringMap = {}
let cloudProject: CloudProject | null = null
// If true, then user is logged in and we fetch the remote project and secrets (if applicable)
if (!opts.noEnterprise && cloudApi) {
const distroName = getCloudDistributionName(cloudApi.domain)
const isCommunityEdition = !config.domain
const cloudLogLevel =
opts.commandInfo.name === "dev" || opts.commandInfo.name === "serve" ? LogLevel.debug : undefined
const cloudLog = log.createLog({ name: getCloudLogSectionName(distroName), fixLevel: cloudLogLevel })

cloudLog.info(`Connecting to ${distroName}...`)
if (!opts.skipCloudConnect && cloudApi) {
cloudLog.info(`Connecting project...`)

cloudProject = await getCloudProject({
cloudApi,
Expand Down Expand Up @@ -1909,6 +1909,10 @@ export const resolveGardenParams = profileAsync(async function _resolveGardenPar
}

cloudLog.success("Ready")
} else if (!opts.skipCloudConnect) {
cloudLog.warn(
`You are not logged in. To use ${distroName}, log in with the ${styles.command("garden login")} command.`
)
}

const loggedIn = !!cloudApi
Expand Down Expand Up @@ -2176,7 +2180,7 @@ export async function makeDummyGarden(root: string, gardenOpts: GardenOpts) {
}
gardenOpts.config = config

return DummyGarden.factory(root, { noEnterprise: true, ...gardenOpts })
return DummyGarden.factory(root, { skipCloudConnect: true, ...gardenOpts })
}

export interface ConfigDump {
Expand Down
2 changes: 1 addition & 1 deletion core/src/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ export class GardenServer extends EventEmitter {
}
} while (!serverStarted)
}
this.log.info(`Garden server has successfully started at port ${styles.highlight(this.port.toString())}.\n`)
this.log.info(`Garden server has successfully started at port ${styles.highlight(this.port.toString())}\n`)

const processRecord = await this.globalConfigStore.get("activeProcesses", String(process.pid))

Expand Down
6 changes: 3 additions & 3 deletions core/src/util/cloud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/
import { DEFAULT_GARDEN_CLOUD_DOMAIN } from "../constants.js"

export type CloudDistroName = "Garden Dashboard" | "Garden Enterprise" | "Garden Cloud"
export type CloudDistroName = "the Garden dashboard" | "Garden Enterprise" | "Garden Cloud"

/**
* Returns "Garden Cloud" if domain matches https://<some-subdomain>.app.garden,
Expand All @@ -17,7 +17,7 @@ export type CloudDistroName = "Garden Dashboard" | "Garden Enterprise" | "Garden
*/
export function getCloudDistributionName(domain: string): CloudDistroName {
if (domain === DEFAULT_GARDEN_CLOUD_DOMAIN) {
return "Garden Dashboard"
return "the Garden dashboard"
}

// TODO: consider using URL object instead.
Expand All @@ -31,7 +31,7 @@ export function getCloudDistributionName(domain: string): CloudDistroName {
export type CloudLogSectionName = "garden-dashboard" | "garden-cloud" | "garden-enterprise"

export function getCloudLogSectionName(distroName: CloudDistroName): CloudLogSectionName {
if (distroName === "Garden Dashboard") {
if (distroName === "the Garden dashboard") {
return "garden-dashboard"
} else if (distroName === "Garden Cloud") {
return "garden-cloud"
Expand Down
22 changes: 11 additions & 11 deletions core/test/unit/src/commands/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ describe("LoginCommand", () => {
}
const command = new LoginCommand()
const garden = await makeTestGarden(getDataDir("test-projects", "login", "has-domain"), {
noEnterprise: false,
skipCloudConnect: false,
commandInfo: { name: "foo", args: {}, opts: {} },
globalConfigStore,
})
Expand All @@ -88,7 +88,7 @@ describe("LoginCommand", () => {
}
const command = new LoginCommand()
const garden = await makeTestGarden(getDataDir("test-projects", "login", "has-domain-and-id"), {
noEnterprise: false,
skipCloudConnect: false,
commandInfo: { name: "foo", args: {}, opts: {} },
globalConfigStore,
})
Expand All @@ -115,7 +115,7 @@ describe("LoginCommand", () => {

const command = new LoginCommand()
const garden = await makeTestGarden(getDataDir("test-projects", "login", "has-domain-and-id"), {
noEnterprise: false,
skipCloudConnect: false,
commandInfo: { name: "foo", args: {}, opts: {} },
globalConfigStore,
})
Expand Down Expand Up @@ -146,7 +146,7 @@ describe("LoginCommand", () => {
// NOTE: if we don't use makeDummyGarden it would try to fully resolve the
// secrets which are not available unless we mock the cloud API instance.
const garden = await makeDummyGarden(getDataDir("test-projects", "login", "secret-in-project-variables"), {
noEnterprise: false,
skipCloudConnect: false,
commandInfo: { name: "foo", args: {}, opts: {} },
globalConfigStore,
})
Expand Down Expand Up @@ -205,7 +205,7 @@ describe("LoginCommand", () => {

const command = new LoginCommand()
const garden = await makeTestGarden(getDataDir("test-projects", "login", "has-domain-and-id"), {
noEnterprise: false,
skipCloudConnect: false,
commandInfo: { name: "foo", args: {}, opts: {} },
globalConfigStore,
})
Expand Down Expand Up @@ -236,7 +236,7 @@ describe("LoginCommand", () => {

const command = new LoginCommand()
const garden = await makeTestGarden(getDataDir("test-projects", "login", "has-domain-and-id"), {
noEnterprise: false,
skipCloudConnect: false,
commandInfo: { name: "foo", args: {}, opts: {} },
globalConfigStore,
})
Expand Down Expand Up @@ -301,7 +301,7 @@ describe("LoginCommand", () => {

// this is a bit of a workaround to run outside of the garden root dir
const garden = await makeDummyGarden(getDataDir("..", "..", "..", ".."), {
noEnterprise: false,
skipCloudConnect: false,
commandInfo: { name: "foo", args: {}, opts: {} },
globalConfigStore,
})
Expand Down Expand Up @@ -338,7 +338,7 @@ describe("LoginCommand", () => {
it("should be a no-op if the user has a valid auth token in the environment", async () => {
const command = new LoginCommand()
const garden = await makeTestGarden(getDataDir("test-projects", "login", "has-domain-and-id"), {
noEnterprise: false,
skipCloudConnect: false,
commandInfo: { name: "foo", args: {}, opts: {} },
globalConfigStore,
})
Expand All @@ -355,7 +355,7 @@ describe("LoginCommand", () => {
it("should throw if the user has an invalid auth token in the environment", async () => {
const command = new LoginCommand()
const garden = await makeTestGarden(getDataDir("test-projects", "login", "has-domain-and-id"), {
noEnterprise: false,
skipCloudConnect: false,
commandInfo: { name: "foo", args: {}, opts: {} },
globalConfigStore,
})
Expand Down Expand Up @@ -388,7 +388,7 @@ describe("LoginCommand", () => {
}
const command = new LoginCommand()
const garden = await makeTestGarden(getDataDir("test-projects", "login", "missing-domain"), {
noEnterprise: false,
skipCloudConnect: false,
commandInfo: { name: "foo", args: {}, opts: {} },
globalConfigStore,
})
Expand Down Expand Up @@ -418,7 +418,7 @@ describe("LoginCommand", () => {
}
const command = new LoginCommand()
const garden = await makeTestGarden(getDataDir("test-projects", "login", "has-domain"), {
noEnterprise: false,
skipCloudConnect: false,
commandInfo: { name: "foo", args: {}, opts: {} },
globalConfigStore,
})
Expand Down
12 changes: 6 additions & 6 deletions core/test/unit/src/commands/logout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe("LogoutCommand", () => {

const command = new LogOutCommand()
const garden = await makeTestGarden(getDataDir("test-projects", "login", "has-domain-and-id"), {
noEnterprise: false,
skipCloudConnect: false,
commandInfo: { name: "foo", args: {}, opts: {} },
globalConfigStore,
})
Expand Down Expand Up @@ -95,7 +95,7 @@ describe("LogoutCommand", () => {

const command = new LogOutCommand()
const garden = await makeTestGarden(getDataDir("test-projects", "login", "missing-domain"), {
noEnterprise: false,
skipCloudConnect: false,
commandInfo: { name: "foo", args: {}, opts: {} },
})

Expand Down Expand Up @@ -126,7 +126,7 @@ describe("LogoutCommand", () => {
it("should be a no-op if the user is already logged out", async () => {
const command = new LogOutCommand()
const garden = await makeTestGarden(getDataDir("test-projects", "login", "has-domain-and-id"), {
noEnterprise: false,
skipCloudConnect: false,
commandInfo: { name: "foo", args: {}, opts: {} },
globalConfigStore,
})
Expand All @@ -147,7 +147,7 @@ describe("LogoutCommand", () => {

const command = new LogOutCommand()
const garden = await makeTestGarden(getDataDir("test-projects", "login", "has-domain-and-id"), {
noEnterprise: false,
skipCloudConnect: false,
commandInfo: { name: "foo", args: {}, opts: {} },
globalConfigStore,
})
Expand Down Expand Up @@ -187,7 +187,7 @@ describe("LogoutCommand", () => {

const command = new LogOutCommand()
const garden = await makeTestGarden(getDataDir("test-projects", "login", "has-domain-and-id"), {
noEnterprise: false,
skipCloudConnect: false,
commandInfo: { name: "foo", args: {}, opts: {} },
globalConfigStore,
})
Expand Down Expand Up @@ -245,7 +245,7 @@ describe("LogoutCommand", () => {

// this is a bit of a workaround to run outside of the garden root dir
const garden = await makeDummyGarden(getDataDir("..", "..", "..", ".."), {
noEnterprise: false,
skipCloudConnect: false,
commandInfo: { name: "foo", args: {}, opts: {} },
globalConfigStore,
})
Expand Down
Loading

0 comments on commit c1d2007

Please sign in to comment.