Skip to content

Commit

Permalink
add optional login to init command
Browse files Browse the repository at this point in the history
  • Loading branch information
Roy Razon committed Oct 18, 2023
1 parent ebd5c5a commit 20bd6bc
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 29 deletions.
32 changes: 32 additions & 0 deletions packages/cli/docs/login.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
`preevy login`
==============

Login to the Livecycle SaaS

* [`preevy login`](#preevy-login)

## `preevy login`

Login to the Livecycle SaaS

```
USAGE
$ preevy login [-D] [-f <value>] [--system-compose-file <value>] [-p <value>] [--lc-auth-url <value>]
[--lc-api-url <value>] [--lc-client-id <value>]
FLAGS
--lc-api-url=<value> [default: https://app.livecycle.run] The Livecycle API URL'
--lc-auth-url=<value> [default: https://auth.livecycle.dev] The login URL
--lc-client-id=<value> [default: BHXcVtapfKPEpZtYO3AJ2Livmz6j7xK0] The client ID for the OAuth app
GLOBAL FLAGS
-D, --debug Enable debug logging
-f, --file=<value>... [default: ] Compose configuration file
-p, --project=<value> Project name. Defaults to the Compose project name
--system-compose-file=<value>... [default: ] Add extra Compose configuration file without overriding the defaults
DESCRIPTION
Login to the Livecycle SaaS
```

_See code: [dist/commands/login.ts](https://github.com/livecycle/preevy/blob/v0.0.55/packages/cli/src/commands/login.ts)_
1 change: 1 addition & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"/oclif.manifest.json"
],
"dependencies": {
"@inquirer/confirm": "^2.0.14",
"@oclif/core": "^2",
"@oclif/plugin-help": "^5",
"@preevy/cli-common": "0.0.55",
Expand Down
48 changes: 25 additions & 23 deletions packages/cli/src/commands/init.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { Flags, Args, ux } from '@oclif/core'
import { Flag } from '@oclif/core/lib/interfaces'
import inquirer from 'inquirer'
import confirm from '@inquirer/confirm'
import chalk from 'chalk'
import { defaultBucketName as gsDefaultBucketName, defaultProjectId as defaultGceProjectId } from '@preevy/driver-gce'
import { defaultBucketName as s3DefaultBucketName, AWS_REGIONS, awsUtils } from '@preevy/driver-lightsail'
import { BaseCommand } from '@preevy/cli-common'
import { EOL } from 'os'
import { Flag } from '@oclif/core/lib/interfaces'
import { DriverName, formatDriverFlagsToArgs, machineDrivers } from '../drivers'
import { loadProfileConfig } from '../profile-command'
import ambientAwsAccountId = awsUtils.ambientAccountId
Expand Down Expand Up @@ -127,34 +130,21 @@ export default class Init extends BaseCommand {

async run(): Promise<unknown> {
const profileConfig = loadProfileConfig(this.config)
const existingProfiles = await profileConfig.list()
let profileAlias = this.args['profile-alias']
const profileExists = existingProfiles.find(p => p.alias === profileAlias)
if (profileExists) {
ux.info(`Profile ${profileAlias} already exists`)
ux.info('Use `init <profile-alias>` to create a new profile')
return undefined
const { 'profile-alias': profileAlias } = this.args
if (await profileConfig.get(profileAlias, { throwOnNotFound: false })) {
ux.error([
`A profile with the alias ${chalk.bold(profileAlias)} already exists.`,
`Run ${chalk.bold(`${this.config.bin} profile ls`)} to list existing profiles.`,
`Run ${chalk.bold(`${this.config.bin} profile rm <profile-alias>`)} to remove an existing profile.`,
`Run ${chalk.bold(`${this.config.bin} init <profile-alias>`)} to create a profile with a different alias.`,
].join(EOL))
}

if (this.flags.from) {
await this.config.runCommand('profile:import', [this.flags.from, '--name', profileAlias, '--use'])
this.log('Initialized profile')
return undefined
}

if (profileExists) {
if (profileAlias !== 'default') {
throw new Error(`Profile ${profileAlias} already exists`)
}
profileAlias = await inquirer.prompt<{
profileName: string
}>([{
type: 'input',
name: 'profileAlias',
message: 'What is the name of your profile?',
}])
}

const driver = await chooseDriver()
const driverStatic = machineDrivers[driver]

Expand All @@ -174,7 +164,19 @@ export default class Init extends BaseCommand {
...formatDriverFlagsToArgs(driver, driverStatic.flags as Record<string, Flag<unknown>>, driverFlags),
])

this.log('Initialized profile')
ux.info(chalk.bold.cyan('Use Livecycle together with Preevy to enable easy sharing and collaboration of your environments!'))

if (!await confirm({
message: 'Would you like to link this profile to a Livecycle account?',
default: true,
})) {
ux.info(`You can later run ${chalk.bold(`${this.config.bin} profile link`)} to link this profile to a Livecycle account.`)
return undefined
}

await this.config.runCommand('login')
await this.config.runCommand('profile:link')

return undefined
}
}
6 changes: 5 additions & 1 deletion packages/cli/src/commands/profile/create.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Args, Flags } from '@oclif/core'
import { Args, Flags, ux } from '@oclif/core'
import { createTunnelingKey } from '@preevy/core'
import chalk from 'chalk'
import {
DriverName,
extractDriverFlags,
Expand Down Expand Up @@ -52,6 +53,9 @@ export default class CreateProfile extends ProfileCommand<typeof CreateProfile>
if (this.flags.use) {
await this.profileConfig.setCurrent(alias)
}

ux.info(chalk.greenBright('Profile initialized 👍'))

return undefined
}
}
4 changes: 3 additions & 1 deletion packages/cli/src/commands/profile/import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Args, Flags, ux } from '@oclif/core'
import { find, range, map } from 'iter-tools-es'
import { LocalProfilesConfig } from '@preevy/core'
import { BaseCommand } from '@preevy/cli-common'
import chalk from 'chalk'
import { loadProfileConfig, onProfileChange } from '../../profile-command'

const DEFAULT_ALIAS_PREFIX = 'default'
Expand Down Expand Up @@ -46,9 +47,10 @@ export default class ImportProfile extends BaseCommand<typeof ImportProfile> {

const { info } = await profileConfig.importExisting(alias, this.args.location)
onProfileChange(info, alias, this.args.location)
ux.info(`Profile ${info.id} imported successfully as ${alias}`)
if (this.flags.use) {
await profileConfig.setCurrent(alias)
}

ux.info(`Profile ${chalk.bold(info.id)} imported successfully as ${chalk.bold(alias)} 👍`)
}
}
2 changes: 1 addition & 1 deletion packages/cli/src/profile-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ abstract class ProfileCommand<T extends typeof Command> extends BaseCommand<T> {
#profile: Profile | undefined
get profile(): Profile {
if (!this.#profile) {
this.error(`Profile not initialized, run ${chalk.italic.bold.greenBright('preevy init')} to get started.`)
this.error(`Profile not initialized, run ${chalk.bold(`${this.config.bin} init`)} to get started.`)
}
return this.#profile
}
Expand Down
7 changes: 5 additions & 2 deletions packages/core/src/profile/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,14 @@ export const localProfilesConfig = (
async list(): Promise<ProfileListing[]> {
return Object.entries((await readProfileList()).profiles).map(([alias, profile]) => ({ alias, ...profile }))
},
async get(alias: string) {
async get(alias: string, opts: { throwOnNotFound: boolean } = { throwOnNotFound: true }) {
const { profiles } = await readProfileList()
const locationUrl = profiles[alias]?.location
if (!locationUrl) {
throw new Error(`Profile ${alias} not found`)
if (opts.throwOnNotFound) {
throw new Error(`Profile ${alias} not found`)
}
return undefined
}
const tarSnapshotStore = await tarSnapshotFromUrl(locationUrl)
const profileInfo = await profileStore(tarSnapshotStore).info()
Expand Down
32 changes: 32 additions & 0 deletions site/docs/cli-reference/login.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
`preevy login`
==============

Login to the Livecycle SaaS

* [`preevy login`](#preevy-login)

## `preevy login`

Login to the Livecycle SaaS

```
USAGE
$ preevy login [-D] [-f <value>] [--system-compose-file <value>] [-p <value>] [--lc-auth-url <value>]
[--lc-api-url <value>] [--lc-client-id <value>]
FLAGS
--lc-api-url=<value> [default: https://app.livecycle.run] The Livecycle API URL'
--lc-auth-url=<value> [default: https://auth.livecycle.dev] The login URL
--lc-client-id=<value> [default: BHXcVtapfKPEpZtYO3AJ2Livmz6j7xK0] The client ID for the OAuth app
GLOBAL FLAGS
-D, --debug Enable debug logging
-f, --file=<value>... [default: ] Compose configuration file
-p, --project=<value> Project name. Defaults to the Compose project name
--system-compose-file=<value>... [default: ] Add extra Compose configuration file without overriding the defaults
DESCRIPTION
Login to the Livecycle SaaS
```

_See code: [dist/commands/login.ts](https://github.com/livecycle/preevy/blob/v0.0.55/packages/cli/src/commands/login.ts)_
94 changes: 93 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3064,6 +3064,40 @@
resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340"
integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==

"@inquirer/confirm@^2.0.14":
version "2.0.14"
resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-2.0.14.tgz#b87fcdf218d0ce687bd021623e091d3a80744e9e"
integrity sha512-Elzo5VX5lO1q9xy8CChDtDQNVLaucufdZBAM12qdfX1L3NQ+TypnZytGmWDXHBTpBTwuhEuwxNvUw7B0HCURkw==
dependencies:
"@inquirer/core" "^5.1.0"
"@inquirer/type" "^1.1.5"
chalk "^4.1.2"

"@inquirer/core@^5.1.0":
version "5.1.0"
resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-5.1.0.tgz#2e3f6abf1dee93eae60cd85a5168c52400f73c9c"
integrity sha512-EVnific72BhMOMo8mElvrYhGFWJZ73X6j0I+fITIPTsdAz6Z9A3w3csKy+XaH87/5QAEIQHR7RSCVXvQpIqNdQ==
dependencies:
"@inquirer/type" "^1.1.5"
"@types/mute-stream" "^0.0.2"
"@types/node" "^20.8.2"
"@types/wrap-ansi" "^3.0.0"
ansi-escapes "^4.3.2"
chalk "^4.1.2"
cli-spinners "^2.9.1"
cli-width "^4.1.0"
figures "^3.2.0"
mute-stream "^1.0.0"
run-async "^3.0.0"
signal-exit "^4.1.0"
strip-ansi "^6.0.1"
wrap-ansi "^6.2.0"

"@inquirer/type@^1.1.5":
version "1.1.5"
resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-1.1.5.tgz#b8c171f755859c8159b10e41e1e3a88f0ca99d7f"
integrity sha512-wmwHvHozpPo4IZkkNtbYenem/0wnfI6hvOcGKmPEa0DwuaH5XUQzFqy6OpEpjEegZMhYIk8HDYITI16BPLtrRA==

"@isaacs/string-locale-compare@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz#291c227e93fd407a96ecd59879a35809120e432b"
Expand Down Expand Up @@ -4741,6 +4775,13 @@
resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c"
integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==

"@types/mute-stream@^0.0.2":
version "0.0.2"
resolved "https://registry.yarnpkg.com/@types/mute-stream/-/mute-stream-0.0.2.tgz#5a011b17307364e48591ac6829a8e40e1c10c6b0"
integrity sha512-FpiGjk6+IOrN0lZEfUUjdra1csU1VxwYFj4S0Zj+TJpu5x5mZW30RkEZojTadrNZHNmpCHgoE62IQZAH0OeuIA==
dependencies:
"@types/node" "*"

"@types/node-fetch@^2.6.3":
version "2.6.3"
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.3.tgz#175d977f5e24d93ad0f57602693c435c57ad7e80"
Expand All @@ -4766,6 +4807,13 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-15.14.9.tgz#bc43c990c3c9be7281868bbc7b8fdd6e2b57adfa"
integrity sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A==

"@types/node@^20.8.2":
version "20.8.6"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.6.tgz#0dbd4ebcc82ad0128df05d0e6f57e05359ee47fa"
integrity sha512-eWO4K2Ji70QzKUqRy6oyJWUeB7+g2cRagT3T/nxYibYcT4y2BDL8lqolRXjTHmkZCdJfIPaY73KbJAZmcryxTQ==
dependencies:
undici-types "~5.25.1"

"@types/normalize-package-data@^2.4.0":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301"
Expand Down Expand Up @@ -4906,6 +4954,11 @@
"@types/expect" "^1.20.4"
"@types/node" "*"

"@types/wrap-ansi@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz#18b97a972f94f60a679fd5c796d96421b9abb9fd"
integrity sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==

"@types/ws@^8.5.3":
version "8.5.5"
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb"
Expand Down Expand Up @@ -6149,6 +6202,11 @@ cli-spinners@^2.5.0:
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.7.0.tgz#f815fd30b5f9eaac02db604c7a231ed7cb2f797a"
integrity sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==

cli-spinners@^2.9.1:
version "2.9.1"
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.1.tgz#9c0b9dad69a6d47cbb4333c14319b060ed395a35"
integrity sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==

cli-table@^0.3.1:
version "0.3.11"
resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.11.tgz#ac69cdecbe81dccdba4889b9a18b7da312a9d3ee"
Expand All @@ -6169,6 +6227,11 @@ cli-width@^3.0.0:
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==

cli-width@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5"
integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==

cliui@^7.0.2:
version "7.0.4"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
Expand Down Expand Up @@ -7878,7 +7941,7 @@ fb-watchman@^2.0.0:
dependencies:
bser "2.1.1"

[email protected], figures@^3.0.0:
[email protected], figures@^3.0.0, figures@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==
Expand Down Expand Up @@ -10962,6 +11025,11 @@ [email protected], mute-stream@~0.0.4:
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==

mute-stream@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e"
integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==

nan@^2.17.0:
version "2.17.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb"
Expand Down Expand Up @@ -12996,6 +13064,11 @@ run-async@^2.0.0, run-async@^2.4.0:
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==

run-async@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/run-async/-/run-async-3.0.0.tgz#42a432f6d76c689522058984384df28be379daad"
integrity sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==

run-parallel@^1.1.9:
version "1.2.0"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
Expand Down Expand Up @@ -13215,6 +13288,11 @@ signal-exit@^4.0.1:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.0.1.tgz#96a61033896120ec9335d96851d902cc98f0ba2a"
integrity sha512-uUWsN4aOxJAS8KOuf3QMyFtgm1pkb6I+KRZbRF/ghdf5T7sM+B1lLLzPDxswUjkmHyxQAVzEgG35E3NzDM9GVw==

signal-exit@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==

sigstore@^1.0.0, sigstore@^1.3.0, sigstore@^1.4.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/sigstore/-/sigstore-1.5.0.tgz#795e44b8e9ab0089daa90eff792a831ba87ffe9c"
Expand Down Expand Up @@ -14275,6 +14353,11 @@ underscore@^1.13.6:
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.6.tgz#04786a1f589dc6c09f761fc5f45b89e935136441"
integrity sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==

undici-types@~5.25.1:
version "5.25.3"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.25.3.tgz#e044115914c85f0bcbb229f346ab739f064998c3"
integrity sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==

unique-filename@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230"
Expand Down Expand Up @@ -14638,6 +14721,15 @@ wrap-ansi@^2.0.0:
string-width "^1.0.1"
strip-ansi "^3.0.1"

wrap-ansi@^6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"

wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
Expand Down

0 comments on commit 20bd6bc

Please sign in to comment.