Skip to content
This repository has been archived by the owner on Feb 13, 2024. It is now read-only.

Commit

Permalink
Credential explorer (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
itowlson authored Sep 26, 2018
1 parent afc7c53 commit 3f59e18
Show file tree
Hide file tree
Showing 10 changed files with 391 additions and 3 deletions.
16 changes: 16 additions & 0 deletions images/dark/add.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions images/light/add.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
77 changes: 76 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,15 @@
"onCommand:duffle.build",
"onCommand:duffle.publish",
"onCommand:duffle.install",
"onCommand:duffle.generateCredentials",
"onCommand:duffle.refreshRepoExplorer",
"onCommand:duffle.refreshCredentialExplorer",
"onCommand:duffle.credentialsetAdd",
"onCommand:duffle.credentialsetDelete",
"onCommand:duffle.exposeParameter",
"onView:duffle.bundleExplorer",
"onView:duffle.repoExplorer",
"onView:duffle.credentialExplorer",
"onLanguage:json"
],
"main": "./out/extension",
Expand Down Expand Up @@ -75,6 +80,11 @@
"title": "Install Bundle",
"category": "Duffle"
},
{
"command": "duffle.generateCredentials",
"title": "Generate Bundle Credential Set",
"category": "Duffle"
},
{
"command": "duffle.refreshRepoExplorer",
"title": "Refresh Repo Explorer",
Expand All @@ -84,6 +94,29 @@
"dark": "images/dark/refresh.svg"
}
},
{
"command": "duffle.refreshCredentialExplorer",
"title": "Refresh Credential Explorer",
"category": "Duffle",
"icon": {
"light": "images/light/refresh.svg",
"dark": "images/dark/refresh.svg"
}
},
{
"command": "duffle.credentialsetAdd",
"title": "Add Credential Set",
"category": "Duffle",
"icon": {
"light": "images/light/add.svg",
"dark": "images/dark/add.svg"
}
},
{
"command": "duffle.credentialsetDelete",
"title": "Delete Credential Set",
"category": "Duffle"
},
{
"command": "duffle.exposeParameter",
"title": "Expose as CNAB Parameter",
Expand Down Expand Up @@ -116,6 +149,16 @@
"command": "duffle.refreshRepoExplorer",
"when": "view == duffle.repoExplorer",
"group": "navigation"
},
{
"command": "duffle.refreshCredentialExplorer",
"when": "view == duffle.credentialExplorer",
"group": "navigation"
},
{
"command": "duffle.credentialsetAdd",
"when": "view == duffle.credentialExplorer",
"group": "navigation"
}
],
"view/item/context": [
Expand All @@ -138,6 +181,16 @@
"command": "duffle.install",
"when": "view == duffle.repoExplorer && viewItem == duffle.repoBundle",
"group": "1"
},
{
"command": "duffle.generateCredentials",
"when": "view == duffle.repoExplorer && viewItem == duffle.repoBundle",
"group": "1"
},
{
"command": "duffle.credentialsetDelete",
"when": "view == duffle.credentialExplorer && viewItem == duffle.credentialset",
"group": "1"
}
],
"explorer/context": [
Expand All @@ -146,6 +199,11 @@
"when": "resourceFilename == bundle.json",
"group": "9"
},
{
"command": "duffle.generateCredentials",
"when": "resourceFilename == bundle.json",
"group": "9"
},
{
"command": "duffle.publish",
"when": "resourceFilename == bundle.json",
Expand Down Expand Up @@ -178,6 +236,19 @@
"command": "duffle.refreshRepoExplorer",
"when": "view == duffle.repoExplorer"
},
{
"command": "duffle.refreshCredentialExplorer",
"when": "view == duffle.credentialExplorer"
},
{
"command": "duffle.credentialsetAdd",
"when": "view == duffle.credentialExplorer"
},
{
"command": "duffle.credentialsetDelete",
"when": "view == duffle.credentialExplorer && viewItem = duffle.credentialset",
"group": "navigation"
},
{
"command": "duffle.exposeParameter",
"when": "editorLangId == json",
Expand Down Expand Up @@ -209,6 +280,10 @@
{
"id": "duffle.repoExplorer",
"name": "Repositories"
},
{
"id": "duffle.credentialExplorer",
"name": "Credentials"
}
]
}
Expand Down Expand Up @@ -239,4 +314,4 @@
"type": "git",
"url": "https://github.com/deis/duffle-vscode"
}
}
}
72 changes: 72 additions & 0 deletions src/commands/generatecredentials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import * as vscode from 'vscode';
import * as path from 'path';

import { longRunning, showDuffleResult, refreshCredentialExplorer } from '../utils/host';
import * as duffle from '../duffle/duffle';
import { RepoBundle, RepoBundleRef } from '../duffle/duffle.objectmodel';
import { succeeded, map, Errorable } from '../utils/errorable';
import * as shell from '../utils/shell';
import { cantHappen } from '../utils/never';
import { promptBundle, BundleSelection, fileBundleSelection, repoBundleSelection } from '../utils/bundleselection';

export async function generateCredentials(target?: any): Promise<void> {
if (!target) {
return await generateCredentialsPrompted();
}
if (target.scheme) {
return await generateCredentialsForFile(target as vscode.Uri);
}
if (target.bundle) {
return await generateCredentialsForRepoBundle((target as RepoBundleRef).bundle);
}
await vscode.window.showErrorMessage("Internal error: unexpected command target");
}

async function generateCredentialsPrompted(): Promise<void> {
const bundlePick = await promptBundle("Select the bundle to generate credentials for");

if (!bundlePick) {
return;
}

return await generateCredentialsCore(bundlePick);
}

async function generateCredentialsForFile(file: vscode.Uri): Promise<void> {
if (file.scheme !== 'file') {
vscode.window.showErrorMessage("This command requires a filesystem bundle");
return;
}
return await generateCredentialsCore(fileBundleSelection(file));
}

async function generateCredentialsForRepoBundle(bundle: RepoBundle): Promise<void> {
return await generateCredentialsCore(repoBundleSelection(bundle));
}

async function generateCredentialsCore(bundlePick: BundleSelection): Promise<void> {
const generateResult = await generateCredentialsTo(bundlePick, bundlePick.label);

if (succeeded(generateResult)) {
await refreshCredentialExplorer();
}

await showDuffleResult('generate credentials', (bundleId) => bundleId, generateResult);
}

async function generateCredentialsTo(bundlePick: BundleSelection, credentialSetName: string): Promise<Errorable<string>> {
if (bundlePick.kind === 'folder') {
const folderPath = bundlePick.path;
const bundlePath = path.join(folderPath, "cnab", "bundle.json");
const generateResult = await longRunning(`Duffle generating credentials for ${bundlePath}`,
() => duffle.generateCredentialsForFile(shell.shell, bundlePath, credentialSetName)
);
return map(generateResult, (_) => bundlePath);
} else if (bundlePick.kind === 'repo') {
const installResult = await longRunning(`Duffle generating credentials for ${bundlePick.bundle}`,
() => duffle.generateCredentialsForBundle(shell.shell, bundlePick.bundle, credentialSetName)
);
return map(installResult, (_) => bundlePick.bundle);
}
return cantHappen(bundlePick);
}
4 changes: 4 additions & 0 deletions src/duffle/duffle.objectmodel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ export interface ParameterDefinition {
readonly defaultValue?: number | string | boolean;
readonly metadata?: { description?: string };
}

export interface CredentialSetRef {
readonly credentialSetName: string;
}
27 changes: 27 additions & 0 deletions src/duffle/duffle.paths.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as path from 'path';

export function credentialSetPath(name: string): string {
return path.join(credentialSetDir(), name + '.yaml');
}

function home(): string {
const envHome = process.env['DUFFLE_HOME'];
if (envHome) {
return envHome;
}

return path.join(osHome(), '.duffle');
}

function osHome(): string {
const homeEnvPath = process.env["HOME"];
if (homeEnvPath) {
return homeEnvPath;
}

return process.env["USERPROFILE"] || '';
}

function credentialSetDir(): string {
return path.join(home(), 'credentials');
}
26 changes: 26 additions & 0 deletions src/duffle/duffle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ export function listRepos(sh: shell.Shell): Promise<Errorable<string[]>> {
return invokeObj(sh, 'repo list', '', {}, parse);
}

export function listCredentialSets(sh: shell.Shell): Promise<Errorable<string[]>> {
function parse(stdout: string): string[] {
return stdout.split('\n')
.map((l) => l.trim())
.filter((l) => l.length > 0);
}
return invokeObj(sh, 'credentials list', '', {}, parse);
}

export function search(sh: shell.Shell): Promise<Errorable<RepoBundle[]>> {
function parse(stdout: string): RepoBundle[] {
const lines = stdout.split('\n')
Expand Down Expand Up @@ -119,3 +128,20 @@ function asObj<T>(labels: string[], columns: string[]): T {
}
return o;
}

export async function addCredentialSets(sh: shell.Shell, files: string[]): Promise<Errorable<null>> {
const filesArg = files.map((f) => `"${f}"`).join(' ');
return await invokeObj(sh, 'credential add', filesArg, {}, (s) => null);
}

export async function deleteCredentialSet(sh: shell.Shell, credentialSetName: string): Promise<Errorable<null>> {
return await invokeObj(sh, 'credential remove', credentialSetName, {}, (s) => null);
}

export async function generateCredentialsForFile(sh: shell.Shell, bundleFilePath: string, name: string): Promise<Errorable<null>> {
return await invokeObj(sh, 'credentials generate', `${name} -f "${bundleFilePath}"`, {}, (s) => null);
}

export async function generateCredentialsForBundle(sh: shell.Shell, bundleName: string, name: string): Promise<Errorable<null>> {
return await invokeObj(sh, 'credentials generate', `${name} ${bundleName}`, {}, (s) => null);
}
Loading

0 comments on commit 3f59e18

Please sign in to comment.