diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c64e25f..f3790ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,7 +57,5 @@ jobs: - name: Install dependencies run: lute run install - # MUS-2103 TODO: This will error in CI until Foreman is updated to install - # the correct linux binary for luau-lsp - name: Analyze run: lute run analyze diff --git a/.luaurc b/.luaurc index c1850d7..9bfd3f9 100644 --- a/.luaurc +++ b/.luaurc @@ -4,7 +4,6 @@ "lint": "~/.lute/typedefs/0.1.0/lint", "lute": "~/.lute/typedefs/0.1.0/lute", "std": "~/.lute/typedefs/0.1.0/std", - "examples": "./examples", "pkg": "./pkg", "root": "./src", diff --git a/src/cli/commands/check.luau b/src/cli/commands/check.luau new file mode 100644 index 0000000..f18905d --- /dev/null +++ b/src/cli/commands/check.luau @@ -0,0 +1,46 @@ +local cli = require("@pkg/cli") +local fs = require("@std/fs") +local path = require("@std/path") +local process = require("@std/process") + +local constants = require("@root/constants") +local parseProjectPath = require("@root/cli/parsers/parseProjectPath") +local readManifest = require("@root/manifest/readManifest") +local types = require("@root/cli/types") + +local ASSET_MANIFEST_FILENAME = constants.ASSET_MANIFEST_FILENAME + +local args = cli.parser() + +args:add("project-path", "option", { + help = `Path to a directory containing an {ASSET_MANIFEST_FILENAME} file`, + aliases = { "p" }, +}) + +local command: types.Subcommand = { + parser = args, + run = function() + local projectPath = parseProjectPath(args, "project-path") + local manifestPath = path.join(projectPath, ASSET_MANIFEST_FILENAME) + + if not fs.exists(projectPath) then + print(`failed to find the project at {projectPath}. does the directory exist?`) + process.exit(1) + return + end + + local success, err = pcall(function() + readManifest(projectPath) + return nil + end) + + if not success then + print(err) + process.exit(1) + end + + print(`manifest at {manifestPath} is valid`) + end, +} + +return command diff --git a/src/cli/commands/publish.luau b/src/cli/commands/publish.luau new file mode 100644 index 0000000..6597054 --- /dev/null +++ b/src/cli/commands/publish.luau @@ -0,0 +1,41 @@ +local cli = require("@pkg/cli") + +local parseApiKey = require("@root/cli/parsers/parseApiKey") +local parseProjectPath = require("@root/cli/parsers/parseProjectPath") +local publishPackageAsync = require("@root/requests/publishPackageAsync") +local publishWorkspaceAsync = require("@root/requests/publishWorkspaceAsync") +local types = require("@root/cli/types") + +local args = cli.parser() + +args:add("asset", "option", { + help = "Name of one of the assets defined in rbxasset.toml that will be published", + aliases = { "a" }, +}) +args:add("project-path", "option", { + help = "Path to a directory containing an rbxasset.toml manifest", + aliases = { "c" }, +}) +args:add("api-key", "option", { + help = "Open Cloud API key with `asset:read` and `asset:write` scopes", + aliases = { "k" }, +}) + +local command: types.Subcommand = { + parser = args, + run = function() + local projectPath = parseProjectPath(args, "project-path") + local apiKey = parseApiKey(args, "api-key") + local assetName = args:get("asset") + + print(`using project at {projectPath}`) + + if assetName then + publishPackageAsync(projectPath, assetName, apiKey) + else + publishWorkspaceAsync(projectPath, apiKey) + end + end, +} + +return command diff --git a/src/cli/init.luau b/src/cli/init.luau new file mode 100644 index 0000000..3c80fb6 --- /dev/null +++ b/src/cli/init.luau @@ -0,0 +1,48 @@ +local process = require("@std/process") + +local check = require("@self/commands/check") +local publish = require("@self/commands/publish") +local types = require("@self/types") + +local ARGS = { ... } + +local SUBCOMMANDS: { [string]: types.Subcommand } = { + check = check, + publish = publish, +} + +local function getPossibleSubcommands() + local names: { string } = {} + for subcommandName in SUBCOMMANDS do + table.insert(names, subcommandName) + end + return table.concat(names, ", ") +end + +--[[ + Lute's CLI battery doesn't support subcommands yet, so to work around that + each of our subcommands is a new Parser instance, and this top-level + interface just routes to each subcommand. +]] + +local scriptPath = ARGS[1] +local subcommandName = ARGS[2] +local userArgs = { scriptPath, table.unpack(ARGS, 2, #ARGS) } + +local subcommand = rawget(SUBCOMMANDS, subcommandName) + +if subcommand then + subcommand.parser:parse(userArgs) + subcommand.run() +else + local message = { + `No command named {subcommandName}`, + `Possible subcommands: {getPossibleSubcommands()}`, + "Usage:", + " rbxasset [...options]", + } + print(table.concat(message, "\n")) + + process.exit(1) + return +end diff --git a/src/cli/parsers/parseApiKey.luau b/src/cli/parsers/parseApiKey.luau new file mode 100644 index 0000000..365d3d0 --- /dev/null +++ b/src/cli/parsers/parseApiKey.luau @@ -0,0 +1,22 @@ +local cli = require("@pkg/cli") +local process = require("@std/process") + +local function parseApiKey(parser: cli.Parser, flagName: string) + local apiKey = parser:get(flagName) + + if apiKey and apiKey ~= "" then + return apiKey + else + local apiKeyFromEnv = process.env.ROBLOX_API_KEY + + if apiKeyFromEnv and apiKeyFromEnv ~= "" then + return apiKeyFromEnv + end + end + + error( + `failed to parse Open Cloud API key. Pass the --{flagName} flag or set the ROBLOX_API_KEY environment variable` + ) +end + +return parseApiKey diff --git a/src/cli/parsers/parseProjectPath.luau b/src/cli/parsers/parseProjectPath.luau new file mode 100644 index 0000000..e0b5c20 --- /dev/null +++ b/src/cli/parsers/parseProjectPath.luau @@ -0,0 +1,22 @@ +local cli = require("@pkg/cli") +local fs = require("@std/fs") +local path = require("@std/path") +local process = require("@std/process") + +local function parseProjectPath(parser: cli.Parser, flagName: string): path.path + local userProjectPath = parser:get(flagName) + + if userProjectPath then + local projectPath = path.resolve(userProjectPath) + + if fs.exists(projectPath) then + return projectPath + else + error(`failed to find the project at {projectPath}. does the directory exist?`) + end + else + return process.cwd() + end +end + +return parseProjectPath diff --git a/src/cli/types.luau b/src/cli/types.luau new file mode 100644 index 0000000..0bf30e1 --- /dev/null +++ b/src/cli/types.luau @@ -0,0 +1,10 @@ +local cli = require("@pkg/cli") + +export type Subcommand = { + parser: cli.Parser, + run: () -> (), + + help: string?, +} + +return nil