Skip to content

Commit 63083a2

Browse files
committed
feat: client secret auth
1 parent 04b5b18 commit 63083a2

7 files changed

+109
-66
lines changed

.dataverse-gen.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@
99
"outputRoot": "./src/dataverse-gen"
1010
},
1111
"generateIndex": false,
12-
"generateFormContext": false
12+
"generateFormContext": false,
13+
"generateEntityTypes": true
1314
}

src/DataverseGenArgs.ts

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* eslint-disable sonarjs/cognitive-complexity */
2+
import * as minimist from "minimist";
3+
import { DataverseMetadataService } from "./MetadataService";
4+
export enum DataverseGenCommands {
5+
Init = "init",
6+
Eject = "eject",
7+
Help = "help",
8+
}
9+
const commands: string[] = [DataverseGenCommands.Init, DataverseGenCommands.Eject, DataverseGenCommands.Help];
10+
11+
export class DataverseGenArgs {
12+
constructor(processArgs: string[]) {
13+
const args = minimist(processArgs, {
14+
alias: { environment: "e", tenantId: "t", applicationId: "a", clientSecret: "s" },
15+
});
16+
this.verboseLogging = args.verbose || args.v || false;
17+
this.environmentUrl = args.u || args.e;
18+
this.tenantId = args.t;
19+
this.applicationId = args.applicationId || args.a;
20+
this.clientSecret = args.clientSecret || args.s || args.cs;
21+
this.command = processArgs.find((a) => commands.indexOf(a) > -1);
22+
}
23+
24+
public outputHelp() {
25+
console.log("Usage: npx dataverse-get [command] [-u] [-t] [-a] [-cs]");
26+
console.log(" dataverse-gen : Generates from an existing .dataverse-gen.json file");
27+
console.log(" dataverse-gen init : Adds .dataverse-gen.json config file to your project");
28+
console.log(" dataverse-gen eject : Adds the templates to your project to allow you to customize them!");
29+
console.log(" -u: Optional: The url of the environment to connect to e.g. 'https://myorg.crm.dynamics.com'.");
30+
console.log(" If not provided, the environment is selected from the list created using dataverse-auth");
31+
console.log(" -t: Optional: The Tenant Id if using an application user to connect.");
32+
console.log(" -a: Optional: The Application Id if using an application user to connect.");
33+
console.log(" -s: Optional: The Client Secret if using an application user to connect.");
34+
}
35+
36+
public connectedService?: DataverseMetadataService;
37+
public command?: string;
38+
public environmentUrl: string;
39+
public tenantId?: string;
40+
public applicationId?: string;
41+
public clientSecret?: string;
42+
public verboseLogging = false;
43+
}

src/MetadataService.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,17 @@ export class DataverseMetadataService implements MetadataService {
2727
this.logger = logger || DefaultLogger;
2828
}
2929

30-
async authorize(server: string) {
30+
async authorize(server: string, tenant?: string, appid?: string, secret?: string) {
3131
// Clear cache
3232
this.edmx = undefined;
3333
this.entityMetadataCache = {};
3434
this.server = server;
3535
this.webApi = new NodeWebApi(server);
36-
await this.webApi.authorize();
36+
if (appid && tenant && secret) {
37+
await this.webApi.authorizeWithSecret(tenant, appid, secret);
38+
} else {
39+
await this.webApi.authorize();
40+
}
3741
// eslint-disable-next-line @typescript-eslint/no-explicit-any
3842
this.client = new XrmContextDataverseClient(this.webApi as any as Xrm.WebApi);
3943
// Set Metadata

src/__tests__/helpers.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ import * as fs from "fs";
22
import * as path from "path";
33
import { CodeWriter } from "../CodeWriter";
44
import { DataverseGenOptions } from "../MetadataGeneratorConfig";
5-
import { MetadataService } from "../MetadataService";
5+
import { DataverseMetadataService, MetadataService } from "../MetadataService";
66
import { SchemaModel } from "../SchemaModel";
77
import { FileSystemTemplateProvider } from "../TemplateProvider";
88
import { TypescriptGenerator } from "../TypescriptGenerator";
99
import { ILoggerCallback } from "../Logger";
10+
import { getServerConfig } from "dataverse-ify/lib/webapi/node";
1011

1112
export async function getModel(options: DataverseGenOptions) {
1213
const projectDir = path.resolve(".");
@@ -46,3 +47,10 @@ export async function generateWithModel(defaultOptions: DataverseGenOptions, mod
4647
export const NoLogging: ILoggerCallback = () => {
4748
//noop
4849
};
50+
51+
export async function getAuthorizedMetadataService() {
52+
const config = getServerConfig();
53+
const service = new DataverseMetadataService(NoLogging);
54+
await service.authorize(config.host, config.tenant, config.appid, config.secret);
55+
return service;
56+
}

src/__tests__/integration.metadata-service.test.ts

+4-13
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,19 @@
1-
import { getServerConfig } from "dataverse-ify/lib/webapi/node";
2-
import { DataverseMetadataService } from "../MetadataService";
31
import * as path from "path";
42
import * as fs from "fs";
5-
import { NoLogging } from "./helpers";
3+
import { getAuthorizedMetadataService } from "./helpers";
64

75
describe("MetadataService", () => {
8-
const config = getServerConfig();
96
const projectDir = path.resolve(".");
107

118
it("downloads EMDX", async () => {
12-
const service = new DataverseMetadataService(NoLogging);
13-
const server = config.host as string;
14-
await service.authorize(server);
9+
const service = await getAuthorizedMetadataService();
1510
const edmx = await service.getEdmxMetadata();
1611
expect(edmx).toBeDefined();
1712
fs.writeFileSync(path.join(projectDir, "src/__tests__/data/edmx.xml"), edmx);
1813
}, 1000000);
1914

2015
it("downloads entity metadata", async () => {
21-
const service = new DataverseMetadataService(NoLogging);
22-
const server = config.host as string;
23-
await service.authorize(server);
16+
const service = await getAuthorizedMetadataService();
2417
const metadata = await service.getEntityMetadata("account");
2518
metadata.ServerVersionStamp = undefined;
2619

@@ -59,9 +52,7 @@ describe("MetadataService", () => {
5952
}, 1000000);
6053

6154
it("handles unknown entities", async () => {
62-
const service = new DataverseMetadataService(NoLogging);
63-
const server = config.host as string;
64-
await service.authorize(server);
55+
const service = await getAuthorizedMetadataService();
6556
const entityMetadata = await service.getEntityMetadata("foo");
6657
expect(entityMetadata.EntityMetadata).toHaveLength(0);
6758
});

src/__tests__/integration.schema-model.test.ts

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
1-
import { getServerConfig } from "dataverse-ify/lib/webapi/node";
21
import { DataverseMetadataService } from "../MetadataService";
32
import { SchemaModel } from "../SchemaModel";
4-
import { NoLogging } from "./helpers";
3+
import { getAuthorizedMetadataService } from "./helpers";
54

65
describe("SchemaModel", () => {
7-
const config = getServerConfig();
86
let service: DataverseMetadataService;
97
beforeAll(async () => {
10-
const server = config.host as string;
11-
service = new DataverseMetadataService(NoLogging);
12-
await service.authorize(server);
8+
service = await getAuthorizedMetadataService();
139
await service.getEdmxMetadata();
1410
}, 100000);
1511

src/index.ts

+43-43
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import * as chalk from "chalk";
55
import { getAllUsers } from "dataverse-ify/lib/webapi/node/MsalAuth";
66
import * as Enquirer from "enquirer";
77
import * as fs from "fs-extra";
8-
import * as minimist from "minimist";
98
import * as path from "path";
109
import { FileSystemCodeWriter } from "./CodeWriter";
10+
import { DataverseGenArgs, DataverseGenCommands } from "./DataverseGenArgs";
1111
import { DataverseGenOptions } from "./MetadataGeneratorConfig";
1212
import { DataverseMetadataService, MetadataService } from "./MetadataService";
1313
import { SchemaModel } from "./SchemaModel";
@@ -57,32 +57,38 @@ function saveConfig(
5757
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
5858
}
5959

60-
function help(): void {
61-
console.log(" dataverse-gen init : Adds .dataverse-gen.json config file to your project");
62-
console.log(" dataverse-gen eject : Adds the templates to your project to allow you to customize them!");
60+
async function GetMetadataService(args: DataverseGenArgs): Promise<DataverseMetadataService> {
61+
const metadataService = new DataverseMetadataService();
62+
if (args.environmentUrl && args.applicationId && args.tenantId && args.clientSecret) {
63+
console.log(chalk.yellow("Using Client Secret Auth"));
64+
await metadataService.authorize(args.environmentUrl, args.tenantId, args.applicationId, args.clientSecret);
65+
} else if (args.environmentUrl) {
66+
await metadataService.authorize(args.environmentUrl);
67+
} else {
68+
const server = await selectServer();
69+
args.environmentUrl = "https://" + server;
70+
await metadataService.authorize(args.environmentUrl);
71+
}
72+
return metadataService;
6373
}
6474

65-
async function init(): Promise<void> {
75+
async function init(args: DataverseGenArgs): Promise<void> {
6676
const pathToTemplate = path.resolve(packageDir, "../.dataverse-gen.template.json");
6777
const pathToOutput = path.resolve(projectDir, configFileName);
6878

6979
initDataverseGenConfig(pathToOutput, pathToTemplate);
7080

71-
const server = await selectServer();
72-
if (server) {
73-
// Load EDMX
74-
const metadataService = new DataverseMetadataService();
75-
await metadataService.authorize("https://" + server);
81+
// Load EDMX
82+
const metadataService = await GetMetadataService(args);
7683

77-
// Load existing config (if there is one)
78-
const currentConfig = readConfig();
79-
const updates = await updateConfig(currentConfig, metadataService);
84+
// Load existing config (if there is one)
85+
const currentConfig = readConfig();
86+
const updates = await updateConfig(currentConfig, metadataService);
8087

81-
saveConfig(currentConfig, updates);
88+
saveConfig(currentConfig, updates);
8289

83-
if (await generateNow()) {
84-
await generate(server);
85-
}
90+
if (await generateNow()) {
91+
await generate(args);
8692
}
8793
}
8894

@@ -230,19 +236,15 @@ function eject(): void {
230236
fs.copySync(source, target);
231237
}
232238

233-
async function generate(server?: string): Promise<void> {
234-
const selectedServer = server || (await selectServer());
239+
async function generate(args: DataverseGenArgs): Promise<void> {
240+
const metadataService = args.connectedService || (await GetMetadataService(args));
235241
const config: DataverseGenOptions = readConfig();
236-
if (selectedServer) {
237-
const metadataService = new DataverseMetadataService();
238-
await metadataService.authorize("https://" + selectedServer);
239-
const codeWriter = new FileSystemCodeWriter(config);
240-
const templateProvider = new FileSystemTemplateProvider(config);
241-
const model = new SchemaModel(metadataService, config);
242-
await model.generate();
243-
const codeGenerator = new TypescriptGenerator(model, codeWriter, templateProvider, config);
244-
await codeGenerator.generate();
245-
}
242+
const codeWriter = new FileSystemCodeWriter(config);
243+
const templateProvider = new FileSystemTemplateProvider(config);
244+
const model = new SchemaModel(metadataService, config);
245+
await model.generate();
246+
const codeGenerator = new TypescriptGenerator(model, codeWriter, templateProvider, config);
247+
await codeGenerator.generate();
246248
}
247249

248250
async function selectServer(): Promise<string | undefined> {
@@ -296,23 +298,19 @@ async function main(): Promise<void> {
296298
console.log(`dataverse-gen v${version}`);
297299
console.log(chalk.gray("Running from package:" + packageDir));
298300

299-
const args = minimist(process.argv.slice(2));
300-
// Check command arg
301-
const mainArg = args._ && args._[0];
302-
switch (mainArg) {
303-
case "help":
304-
case "h":
305-
case "?":
306-
help();
301+
const args = new DataverseGenArgs(process.argv.slice(2));
302+
switch (args.command) {
303+
case DataverseGenCommands.Help:
304+
args.outputHelp();
307305
break;
308-
case "init":
309-
await init();
306+
case DataverseGenCommands.Init:
307+
await init(args);
310308
break;
311-
case "eject":
309+
case DataverseGenCommands.Eject:
312310
eject();
313311
break;
314312
default:
315-
await generate(args.s);
313+
await generate(args);
316314
break;
317315
}
318316
}
@@ -322,8 +320,10 @@ main().then(
322320
console.log(chalk.green("\nComplete!"));
323321
},
324322
(ex) => {
325-
if (ex.message) {
326-
console.log(chalk.red(`\nError:${ex.message}`));
323+
const message = ex.message || ex;
324+
325+
console.log(chalk.red(`\nError:${message}`));
326+
if (ex.stack) {
327327
console.log(`Stack:${ex.stack}`);
328328
console.log(JSON.stringify(ex));
329329
}

0 commit comments

Comments
 (0)