Skip to content
10 changes: 5 additions & 5 deletions .github/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,21 +78,21 @@ You can install `collie` using our install scripts below

**Linux / Ubuntu**

```
```sh
curl -sf -L https://raw.githubusercontent.com/meshcloud/collie-cli/main/install.sh | sudo bash
```

**Mac OS X**

```
```sh
curl -sf -L https://raw.githubusercontent.com/meshcloud/collie-cli/main/install.sh | sh
```

**Windows**

Simply copy the content of
[`install.ps1`](https://github.com/meshcloud/collie-cli/blob/develop/install.ps1)
and run it in your PowerShell console.
```powershell
irm https://raw.githubusercontent.com/meshcloud/collie-cli/main/install.ps1 | iex
```

### 🚀 Connecting to your clouds

Expand Down
6 changes: 5 additions & 1 deletion flags.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { FLAGS } from "./src/info.ts";
import { isWindows } from "./src/os.ts";

const __dirname = new URL(".", import.meta.url).pathname;
let __dirname = new URL(".", import.meta.url).pathname;
if (isWindows) {
__dirname = __dirname.substring(1); // on windows we have to strip the path so it looks like C:/... instead of /C:/...
}

console.log(FLAGS + ` --import-map=${__dirname}src/import_map.json`);
14 changes: 8 additions & 6 deletions install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ catch {
# Ask user whether to add Collie to the environment variables automatically
$userenv = $(Write-Host "Adding Collie to your Environment-Variables? (y/n)" -NoNewLine -ForegroundColor Green; Read-Host)
if ($userenv -like "y") {
$Reg = "HKCU:Environment"
$OldPath = (Get-ItemProperty -Path $Reg -Name PATH).Path
$NewPath = $OldPath + ";" + $($folder.FullName).ToString()
Set-ItemProperty -Path $Reg -Name PATH -Value $NewPath
Write-Host "Reloading Powershell is required!`n" -ForegroundColor Yellow
$BinDir = $($folder.FullName).ToString()
$User = [EnvironmentVariableTarget]::User
$Path = [Environment]::GetEnvironmentVariable('Path', $User)
if (!(";$Path;".ToLower() -like "*;$BinDir;*".ToLower())) {
[Environment]::SetEnvironmentVariable('Path', "$Path;$BinDir", $User)
$Env:Path += ";$BinDir"
}
}

Write-Host "[OK] Collie CLI successfully installed: '$($folder.FullName)'`n" -ForegroundColor Green
# Done
Write-Output "Run 'collie --help' to get started"
6 changes: 4 additions & 2 deletions src/api/aws/AwsPlatformSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { MarkdownDocument } from "../../model/MarkdownDocument.ts";
import { Dir } from "../../cli/DirectoryGenerator.ts";
import { CLI } from "../../info.ts";
import { PlatformSetup } from "../PlatformSetup.ts";
import { isWindows } from "../../os.ts";

export class AwsPlatformSetup extends PlatformSetup<PlatformConfigAws> {
constructor(private readonly aws: AwsCliFacade) {
Expand All @@ -22,7 +23,8 @@ export class AwsPlatformSetup extends PlatformSetup<PlatformConfigAws> {
const profile = await Select.prompt({
message: "Select an AWS CLI Profile",
options: profiles,
search: true,
search: !isWindows, // see https://github.com/c4spar/deno-cliffy/issues/272#issuecomment-1262197264,
info: true,
});

this.progress("trying to sign in and get account info");
Expand Down Expand Up @@ -54,7 +56,7 @@ export class AwsPlatformSetup extends PlatformSetup<PlatformConfigAws> {
message: `Choose the default AWS region for collie commands`,
default: region,
options: regions.Regions.map((x) => x.RegionName),
search: true,
search: !isWindows, // see https://github.com/c4spar/deno-cliffy/issues/272#issuecomment-1262197264
info: true,
});

Expand Down
3 changes: 2 additions & 1 deletion src/api/az/AzPlatformSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { MarkdownDocument } from "../../model/MarkdownDocument.ts";
import { Dir } from "../../cli/DirectoryGenerator.ts";
import { PlatformSetup } from "../PlatformSetup.ts";
import { MeshError } from "../../errors.ts";
import { isWindows } from "../../os.ts";

export class AzPlatformSetup extends PlatformSetup<PlatformConfigAzure> {
constructor(private readonly az: AzCliFacade) {
Expand All @@ -27,7 +28,7 @@ export class AzPlatformSetup extends PlatformSetup<PlatformConfigAzure> {
name: x.name + " / AAD " + x.tenantId,
value: x.id,
})),
search: true,
search: !isWindows, // see https://github.com/c4spar/deno-cliffy/issues/272#issuecomment-1262197264
info: true,
});

Expand Down
5 changes: 3 additions & 2 deletions src/api/gcloud/GcloudPlatformSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { PlatformSetup } from "../PlatformSetup.ts";
import { GcloudCliFacade } from "./GcloudCliFacade.ts";
import { MeshError } from "../../errors.ts";
import { organizationId } from "./Model.ts";
import { isWindows } from "../../os.ts";

export class GcloudPlatformSetup extends PlatformSetup<PlatformConfigGcp> {
constructor(private readonly gcloud: GcloudCliFacade) {
Expand All @@ -23,7 +24,7 @@ export class GcloudPlatformSetup extends PlatformSetup<PlatformConfigGcp> {
const configurationName = await Select.prompt({
message: "Select a gcloud CLI configuration",
options: configurations.map((x) => x.name),
search: true,
search: !isWindows, // see https://github.com/c4spar/deno-cliffy/issues/272#issuecomment-1262197264
info: true,
});

Expand All @@ -46,7 +47,7 @@ export class GcloudPlatformSetup extends PlatformSetup<PlatformConfigGcp> {
name: x.displayName,
value: x.name,
})),
search: true,
search: !isWindows, // see https://github.com/c4spar/deno-cliffy/issues/272#issuecomment-1262197264,
info: true,
});

Expand Down
20 changes: 20 additions & 0 deletions src/api/git/GitCliDetector.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { GitCliDetector } from "./GitCliDetector.ts";
import { StubProcessRunner } from "../../process/StubProcessRunner.ts";
import { assertEquals } from "std/testing/assert";

Deno.test(
"can parse version numbers",
() => {
const sut = new GitCliDetector(new StubProcessRunner());

const tests = [
["git version 2.19.0", "2.19.0"],
["git version 2.19.0.windows.1", "2.19.0"],
];

tests.forEach(([output, expected]) => {
const actual = sut.parseVersion(output);
assertEquals(actual, expected);
});
},
);
10 changes: 6 additions & 4 deletions src/api/git/GitCliDetector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@ export class GitCliDetector extends CliDetector {
super("git", runner);
}

protected parseVersion(versionCmdOutput: string): string {
const components = versionCmdOutput.split(" ");
public parseVersion(versionCmdOutput: string): string {
// some git version strings have additional build info in them, so we only extract what looks like a version number
const versionRegex = /\d+.\d+.\d+/g;

const version = components[0].substring("git version ".length);
const matches = versionCmdOutput.match(versionRegex);

return version;
return (matches && matches[0]) || "";
}

protected isSupportedVersion(version: string): boolean {
// a simple lexicographic comparison is sufficient for our needs

return version > "2.0.0";
}
}
2 changes: 1 addition & 1 deletion src/commands/foundation/PlatformModuleType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class PlatformModuleType extends StringType {
}

static parseModuleId(matchedPath: string) {
const components = matchedPath.split("/");
const components = matchedPath.split(path.SEP);
const platformIndex = components.lastIndexOf("platforms");

const dropTerragruntHclComponent = -1;
Expand Down
2 changes: 2 additions & 0 deletions src/commands/foundation/new.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ async function promptPlatformEntries(
name: "action",
message: "Select an action to continue",
type: Select,
info: true,
options: [
{ value: "add", name: `${colors.green("+")} add cloud platform` },
{ value: "done", name: `${colors.green("✔")} save & exit` },
Expand Down Expand Up @@ -109,6 +110,7 @@ async function promptPlatformEntries(
name: "cloud",
message: "What type of cloud do you want to add",
type: Select,
info: true,
options: [
{ value: "aws", name: "AWS" },
{ value: "azure", name: "Azure" },
Expand Down
3 changes: 2 additions & 1 deletion src/commands/interactive/interactive.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { CollieRepository } from "../../model/CollieRepository.ts";
import { InteractivePrompts } from "./InteractivePrompts.ts";
import { prepareTenantCommand } from "../tenant/prepareTenantCommand.ts";
import { detailViewTenant } from "./detailViewTenant.ts";
import { isWindows } from "../../os.ts";

export function registerInteractiveCommand(program: Command) {
program
Expand Down Expand Up @@ -65,7 +66,7 @@ export async function startInteractiveMode(options: GlobalCommandOptions) {
name:
`${x.platformTenantName} (${x.platformId} ${x.platformTenantId})`,
})),
search: true,
search: !isWindows, // see https://github.com/c4spar/deno-cliffy/issues/272#issuecomment-1262197264
info: true,
});

Expand Down
10 changes: 7 additions & 3 deletions src/commands/kit/apply.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { InteractivePrompts } from "../interactive/InteractivePrompts.ts";
import { KitModuleRepository } from "../../kit/KitModuleRepository.ts";
import { CommandOptionError } from "../CommandOptionError.ts";
import { PlatformConfig } from "../../model/PlatformConfig.ts";
import { isWindows } from "../../os.ts";

interface ApplyOptions {
foundation?: string;
Expand Down Expand Up @@ -176,7 +177,10 @@ EOF
}

function generateTerragrunt(kitModulePath: string) {
const isBootstrap = kitModulePath.endsWith("/bootstrap");
const isBootstrap = kitModulePath.endsWith(`${path.SEP}bootstrap`);

// terragrunt needs a posix style path
const posixKitModulePath = kitModulePath.replaceAll("\\", "/");

const platformIncludeBlock = `include "platform" {
path = find_in_parent_folders("platform.hcl")
Expand All @@ -200,7 +204,7 @@ EOF
}`;

const terraformBlock = `terraform {
source = "\${get_repo_root()}//${kitModulePath}"
source = "\${get_repo_root()}//${posixKitModulePath}"
}`;

const inputsBlock = `inputs = {
Expand All @@ -225,6 +229,6 @@ async function selectModule(moduleRepo: KitModuleRepository) {
message: "Select a kit module from your repository",
options,
info: true,
search: true,
search: !isWindows, // see https://github.com/c4spar/deno-cliffy/issues/272#issuecomment-1262197264
});
}
4 changes: 3 additions & 1 deletion src/kit/KitModuleParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,10 @@ export class KitModuleParser {
return;
}

const posixRelativeModulePath = relativeModulePath.replaceAll("\\", "/");

return {
id: relativeModulePath.substring("kit/".length),
id: posixRelativeModulePath.substring("kit/".length),
kitModulePath: relativeModulePath,
definitionPath: relativeReadmePath,
kitModule: parsed.frontmatter,
Expand Down
3 changes: 2 additions & 1 deletion src/process/QuietProcessRunner.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ProcessRunnerOptions } from "./ProcessRunnerOptions.ts";
import { IProcessRunner } from "./IProcessRunner.ts";
import { ProcessResultWithOutput } from "./ProcessRunnerResult.ts";
import { ShellRunnerPolicy } from "./ShellRunnerPolicy.ts";

/**
* Runs a subprocess quietly by buffering its stdout and stderr in memory until completion.
Expand All @@ -13,7 +14,7 @@ export class QuietProcessRunner
): Promise<ProcessResultWithOutput> {
const p = Deno.run({
...options,
cmd: commands,
cmd: ShellRunnerPolicy.shellCommands(commands),
stdout: "piped",
stderr: "piped",
});
Expand Down
14 changes: 14 additions & 0 deletions src/process/ShellRunnerPolicy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { isWindows } from "../os.ts";

export class ShellRunnerPolicy {
static shellCommands(commands: string[]) {
// on windows, we need run through the user's shell as otherwise we have to run e.g. az.exe instead of az
if (isWindows) {
return ["cmd.exe", "/c", ...commands];
}

// on unix, don't run through the user's shell as that will incur cost of running shell setup (e.g. .bashrc)
// for every new process that we spawn, and collie typcially spawns many
return commands;
}
}
3 changes: 2 additions & 1 deletion src/process/TransparentProcessRunner.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ProcessResult } from "./ProcessRunnerResult.ts";
import { ProcessRunnerOptions } from "./ProcessRunnerOptions.ts";
import { IProcessRunner } from "./IProcessRunner.ts";
import { ShellRunnerPolicy } from "./ShellRunnerPolicy.ts";

/**
* Runs a subprocess transaprently by connecting it to collie's stdout/stderr.
Expand All @@ -13,7 +14,7 @@ export class TransparentProcessRunner implements IProcessRunner<ProcessResult> {
): Promise<ProcessResult> {
const p = Deno.run({
...options,
cmd: commands,
cmd: ShellRunnerPolicy.shellCommands(commands),
stdout: "inherit",
stderr: "inherit",
});
Expand Down