Skip to content

Commit

Permalink
feat(cli): add get module(s) command
Browse files Browse the repository at this point in the history
Closes #2038
  • Loading branch information
edvald committed Sep 9, 2020
1 parent b771949 commit 854509c
Show file tree
Hide file tree
Showing 5 changed files with 443 additions and 0 deletions.
89 changes: 89 additions & 0 deletions core/src/commands/get/get-modules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (C) 2018-2020 Garden Technologies, Inc. <[email protected]>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

import { Command, CommandParams, PrepareParams } from "../base"
import { StringsParameter, BooleanParameter } from "../../cli/params"
import { moduleSchema, GardenModule } from "../../types/module"
import { keyBy, omit, sortBy } from "lodash"
import { joiIdentifierMap, joi } from "../../config/common"
import { printHeader } from "../../logger/util"
import chalk from "chalk"
import { renderTable, dedent } from "../../util/string"
import { relative, sep } from "path"

const getModulesArgs = {
modules: new StringsParameter({
help:
"Specify module(s) to list. Use comma as a separator to specify multiple modules. Skip to return all modules.",
}),
}

const getModulesOptions = {
"exclude-disabled": new BooleanParameter({
help: "Exclude disabled modules from output.",
}),
}

type Args = typeof getModulesArgs
type Opts = typeof getModulesOptions

type OutputModule = Omit<GardenModule, "_config">

export class GetModulesCommand extends Command {
name = "modules"
alias = "module"
help = "Outputs all or specified modules."
description = dedent`
Outputs all or specified modules. Use with --output=json and jq to extract specific fields.
Examples:
garden get modules # list all modules in the project
garden get modules --exclude-disabled=true # skip disabled modules
garden get modules -o=json | jq '.modules["my-module"].version' # get version of my-module
`

arguments = getModulesArgs
options = getModulesOptions

outputsSchema = () => joi.object().keys({ modules: joiIdentifierMap(moduleSchema()) })

async prepare({ headerLog }: PrepareParams<Args, Opts>) {
printHeader(headerLog, "Get Modules", "open_book")
return { persistent: false }
}
async action({ garden, log, args, opts }: CommandParams<Args, Opts>) {
const graph = await garden.getConfigGraph(log)

const modules: OutputModule[] = sortBy(
graph
.getModules({ names: args.modules, includeDisabled: !opts["exclude-disabled"] })
.map((m) => omit(m, "_config")),
"name"
)

const modulesByName = keyBy(modules, "name")

const heading = ["Name", "Version", "Type", "Path"].map((s) => chalk.bold(s))
const rows: string[][] = modules.map((m: OutputModule) => {
const relPath = relative(garden.projectRoot, m.path)

return [
chalk.cyan.bold(m.name),
m.version.versionString,
m.type,
relPath.startsWith("..") ? relPath : "." + sep + relPath,
]
})

log.info("")
log.info(renderTable([heading].concat(rows)))

return { result: { modules: modulesByName } }
}
}
2 changes: 2 additions & 0 deletions core/src/commands/get/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { GetDebugInfoCommand } from "./get-debug-info"
import { GetLinkedReposCommand } from "./get-linked-repos"
import { GetOutputsCommand } from "./get-outputs"
import { GetDoddiCommand } from "./get-doddi"
import { GetModulesCommand } from "./get-modules"

export class GetCommand extends CommandGroup {
name = "get"
Expand All @@ -31,6 +32,7 @@ export class GetCommand extends CommandGroup {
GetEysiCommand,
GetLinkedReposCommand,
GetOutputsCommand,
GetModulesCommand,
GetSecretCommand,
GetStatusCommand,
GetTasksCommand,
Expand Down
79 changes: 79 additions & 0 deletions core/test/unit/src/commands/get/get-modules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (C) 2018-2020 Garden Technologies, Inc. <[email protected]>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

import { expect } from "chai"
import { keyBy, omit, mapValues } from "lodash"
import { makeTestGardenA, withDefaultGlobalOpts } from "../../../../helpers"
import { GetModulesCommand } from "../../../../../src/commands/get/get-modules"

describe("GetModulesCommand", () => {
const command = new GetModulesCommand()

it("returns all modules in a project", async () => {
const garden = await makeTestGardenA()
const log = garden.log

const res = await command.action({
garden,
log,
headerLog: log,
footerLog: log,
args: { modules: undefined },
opts: withDefaultGlobalOpts({ "exclude-disabled": false }),
})

expect(command.outputsSchema().validate(res.result).error).to.be.undefined

const expected = mapValues(keyBy(await garden.resolveModules({ log }), "name"), (m) => omit(m, ["_config"]))

expect(res.result).to.eql({ modules: expected })
})

it("skips disabled modules if exclude-disabled=true", async () => {
const garden = await makeTestGardenA()
const log = garden.log

await garden.scanAndAddConfigs()
garden["moduleConfigs"]["module-a"].disabled = true

const res = await command.action({
garden,
log,
headerLog: log,
footerLog: log,
args: { modules: undefined },
opts: withDefaultGlobalOpts({ "exclude-disabled": true }),
})

expect(command.outputsSchema().validate(res.result).error).to.be.undefined

expect(res.result?.modules["module-a"]).to.not.exist
expect(res.result?.modules["module-b"]).to.exist
})

it("returns specified module in a project", async () => {
const garden = await makeTestGardenA()
const log = garden.log

const res = await command.action({
garden,
log,
headerLog: log,
footerLog: log,
args: { modules: ["module-a"] },
opts: withDefaultGlobalOpts({ "exclude-disabled": false }),
})

expect(command.outputsSchema().validate(res.result).error).to.be.undefined

const graph = await garden.getConfigGraph(log)
const moduleA = graph.getModule("module-a")

expect(res.result).to.eql({ modules: { "module-a": omit(moduleA, ["_config"]) } })
})
})
Loading

0 comments on commit 854509c

Please sign in to comment.