Skip to content

Commit b8c089a

Browse files
committed
feat(run): add debug mode to execute use cases on non-workspaces (#3)
1 parent f5722a1 commit b8c089a

10 files changed

Lines changed: 68 additions & 50 deletions

File tree

README.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,10 @@ the top-level workspace directory.
9191

9292
The following options are available:
9393

94-
| Option | Description |
95-
| --------------------------- | ------------------- |
96-
| `-u, --use-case [use-case]` | the use case to run |
94+
| Option | Description |
95+
| --------------------------- | --------------------------------------------------------------------------------------------------- |
96+
| `-u, --use-case [use-case]` | the use case to run |
97+
| `--debug` | enable debug mode; allows to run use cases from any location, assuming the config structure matches |
9798

9899
For example, to run the `check-requirements` use case, execute:
99100

@@ -395,3 +396,13 @@ After testing, the symlink can be removed via:
395396
```bash
396397
npm uninstall ws-ctrl -g
397398
```
399+
400+
### Use cases
401+
402+
It is possible to test use cases directly in the workspace. To do so, the use case
403+
should be placed in the `assets/templates/config/use-cases` directory.
404+
The use case can then be executed via:
405+
406+
```bash
407+
npm run dev -- run ./assets/templates -u <use-case-name> --debug
408+
```

dist/index.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/commands/init/action.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ export async function init(
6565
const config = initConfig(workspacePath, organization, templatesRepository);
6666

6767
// copy templates from package/repo to workspace
68-
const templatesAccess = TemplatesAccess.create(config);
68+
const templatesAccess = TemplatesAccess.create(config.store);
6969
await templatesAccess.initWorkspace();
7070

71-
const useCaseRunner = UseCaseRunner.create(config, templatesAccess);
71+
const useCaseRunner = UseCaseRunner.create(templatesAccess);
7272
await useCaseRunner.run('init');
7373
}

src/commands/run/run.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,20 @@ const useCaseOption = new Option(
1010
'-u, --use-case [use-case]',
1111
'execute the use case with the given name'
1212
);
13+
const debugOption = new Option('--debug', 'enable debug mode');
1314

1415
interface RunActionOptions {
1516
useCase: OptionInput;
17+
debug: boolean;
1618
}
1719

1820
export async function runAction(
1921
workspacePathRaw: string,
2022
options: RunActionOptions
2123
) {
22-
const config = await loadWorkspaceConfig(workspacePathRaw);
24+
const config = await loadWorkspaceConfig(workspacePathRaw, options.debug);
2325
const templatesAccess = TemplatesAccess.create(config);
24-
const useCaseRunner = UseCaseRunner.create(config, templatesAccess);
26+
const useCaseRunner = UseCaseRunner.create(templatesAccess);
2527
const useCaseRepository = UseCasesRepository.create(templatesAccess);
2628

2729
const useCases = await useCaseRepository.loadUseCases('INITIAL');
@@ -43,4 +45,5 @@ export const run = new Command()
4345
.description('run a use case in the workspace')
4446
.addArgument(defaultWorkspacePathArgument)
4547
.addOption(useCaseOption)
48+
.addOption(debugOption)
4649
.action(runAction);

src/commands/sync/sync.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ async function syncAction(workspacePathRaw: string): Promise<void> {
88
const templatesAccess = TemplatesAccess.create(config);
99
await templatesAccess.syncTemplates();
1010

11-
const useCaseRunner = UseCaseRunner.create(config, templatesAccess);
11+
const useCaseRunner = UseCaseRunner.create(templatesAccess);
1212
await useCaseRunner.run('sync');
1313
}
1414

src/config.ts

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ import Conf from 'conf';
22
import {
33
getWorkspacePathIdentifier,
44
isExistingWorkspace,
5+
logger,
56
resolveWorkspacePath,
67
} from './utils/index.js';
78

8-
interface Config {
9+
export interface Config {
910
workspacePath: string;
1011
organization: string;
1112
templatesRepository: string | null;
@@ -27,6 +28,23 @@ const schema = {
2728

2829
export let config: WorkspaceConfig;
2930

31+
function loadConfig(workspacePath: string): WorkspaceConfig {
32+
config = new Conf<Config>({
33+
schema,
34+
cwd: resolveWorkspacePath(workspacePath),
35+
configName: getWorkspacePathIdentifier(workspacePath),
36+
});
37+
return config;
38+
}
39+
40+
function loadBlankConfig(workspacePath: string): Config {
41+
return {
42+
workspacePath: resolveWorkspacePath(workspacePath),
43+
organization: 'none',
44+
templatesRepository: null,
45+
};
46+
}
47+
3048
export function initConfig(
3149
workspacePath: string,
3250
organization: string,
@@ -39,20 +57,19 @@ export function initConfig(
3957
return config;
4058
}
4159

42-
export function loadConfig(workspacePath: string): WorkspaceConfig {
43-
config = new Conf<Config>({
44-
schema,
45-
cwd: resolveWorkspacePath(workspacePath),
46-
configName: getWorkspacePathIdentifier(workspacePath),
47-
});
48-
return config;
49-
}
50-
51-
export async function loadWorkspaceConfig(workspacePathRaw: string) {
60+
export async function loadWorkspaceConfig(
61+
workspacePathRaw: string,
62+
debug: boolean = false
63+
): Promise<Config> {
5264
const workspacePath = workspacePathRaw.trim();
65+
if (debug) {
66+
logger.log('Running within non-workspace directory...');
67+
return loadBlankConfig(workspacePath);
68+
}
69+
5370
const existingWorkspace = await isExistingWorkspace(workspacePath);
5471
if (!existingWorkspace) {
5572
throw new Error(`The given path is no valid workspace.`);
5673
}
57-
return loadConfig(workspacePath);
74+
return loadConfig(workspacePath).store;
5875
}

src/services/access/templates-access.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { join } from 'node:path';
2-
import { WorkspaceConfig } from '../../config.js';
2+
import { Config } from '../../config.js';
33
import { copyDirectory, gitUpdate, logger } from '../../utils/index.js';
44
import {
55
DIR_CONFIG,
@@ -19,11 +19,11 @@ enum Location {
1919
}
2020

2121
export class TemplatesAccess {
22-
static create(config: WorkspaceConfig): TemplatesAccess {
22+
static create(config: Config): TemplatesAccess {
2323
return new TemplatesAccess(config);
2424
}
2525

26-
constructor(private readonly config: WorkspaceConfig) {}
26+
constructor(private readonly config: Config) {}
2727

2828
getPackageTemplatesDir(): string {
2929
return join(this.#getBaseDir(Location.PACKAGE), DIR_TEMPLATES);
@@ -68,19 +68,19 @@ export class TemplatesAccess {
6868
}
6969

7070
getWorkspacePath(): string {
71-
return this.config.get('workspacePath');
71+
return this.config.workspacePath;
7272
}
7373

7474
getTemplatesRepository(): string | null {
75-
return this.config.get('templatesRepository');
75+
return this.config.templatesRepository;
7676
}
7777

78-
createRepositoryUrl(organization: string, name: string): string {
78+
createRepositoryUrl(name: string): string {
7979
// TODO:
8080
// - add support for HTTPS URLs when provided in config
8181
// - add support for different repository hosts
8282
// - add support for different tenants
83-
return `git@bitbucket.org:${organization}/${name}.git`;
83+
return `git@bitbucket.org:${this.config.organization}/${name}.git`;
8484
}
8585

8686
async initWorkspace(): Promise<void> {
@@ -102,10 +102,7 @@ export class TemplatesAccess {
102102
// sync the templates from the repository if configured
103103
const templatesRepository = this.getTemplatesRepository();
104104
if (templatesRepository) {
105-
const url = this.createRepositoryUrl(
106-
this.config.get('organization'),
107-
templatesRepository
108-
);
105+
const url = this.createRepositoryUrl(templatesRepository);
109106
logger.log(`Syncing templates from repository ${url}...`);
110107

111108
await gitUpdate(url, this.getWorkspacePath(), this.getGitTemplatesDir());

src/services/repositories.repository.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
1-
import { WorkspaceConfig } from '../config.js';
21
import { Repository } from '../types/index.js';
32
import { loadFilesFromDirectory } from '../utils/index.js';
43
import { TemplatesAccess } from './access/index.js';
54

65
export class RepositoriesRepository {
7-
static create(config: WorkspaceConfig, templatesAccess: TemplatesAccess) {
8-
return new RepositoriesRepository(config, templatesAccess);
6+
static create(templatesAccess: TemplatesAccess) {
7+
return new RepositoriesRepository(templatesAccess);
98
}
109

11-
constructor(
12-
private readonly config: WorkspaceConfig,
13-
private readonly templatesAccess: TemplatesAccess
14-
) {}
10+
constructor(private readonly templatesAccess: TemplatesAccess) {}
1511

1612
async loadRepositories(): Promise<Required<Repository>[]> {
1713
return this.loadFiles().then(repositories =>
@@ -31,10 +27,7 @@ export class RepositoriesRepository {
3127
alias: repository.alias || repository.name,
3228
url:
3329
repository.url ||
34-
this.templatesAccess.createRepositoryUrl(
35-
this.config.get('organization'),
36-
repository.name
37-
),
30+
this.templatesAccess.createRepositoryUrl(repository.name),
3831
attributes: {
3932
type: 'UNKNOWN',
4033
...repository.attributes,

src/services/use-cases/context-creator.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
import { WorkspaceConfig } from '../../config.js';
21
import { Context } from '../../types/index.js';
32
import { TemplatesAccess } from '../access/index.js';
43
import { RepositoriesRepository } from '../repositories.repository.js';
54
import { ServersRepository } from '../servers.repository.js';
65

76
export class ContextCreator {
8-
static create(config: WorkspaceConfig, templatesAccess: TemplatesAccess) {
7+
static create(templatesAccess: TemplatesAccess) {
98
return new ContextCreator(
109
templatesAccess,
1110
ServersRepository.create(templatesAccess),
12-
RepositoriesRepository.create(config, templatesAccess)
11+
RepositoriesRepository.create(templatesAccess)
1312
);
1413
}
1514

src/services/use-cases/use-case-runner.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { WorkspaceConfig } from '../../config.js';
21
import { Context, UseCase, UseCaseStep } from '../../types/index.js';
32
import {
43
bold,
@@ -16,14 +15,13 @@ import { executorMapping } from './executors/index.js';
1615

1716
export class UseCaseRunner {
1817
static create(
19-
config: WorkspaceConfig,
2018
templatesAccess: TemplatesAccess,
2119
scriptExecutor?: ScriptExecutor
2220
): UseCaseRunner {
2321
return new UseCaseRunner(
2422
templatesAccess,
2523
UseCasesRepository.create(templatesAccess),
26-
ContextCreator.create(config, templatesAccess),
24+
ContextCreator.create(templatesAccess),
2725
scriptExecutor || ScriptExecutor.create()
2826
);
2927
}

0 commit comments

Comments
 (0)