Skip to content

Commit 7ee5ba0

Browse files
committed
improve config handling
1 parent 84f4188 commit 7ee5ba0

File tree

7 files changed

+145
-91
lines changed

7 files changed

+145
-91
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,5 @@ dist
105105

106106
# typescript output
107107
lib/
108+
109+
testingbot.json

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"devDependencies": {
1919
"@types/archiver": "^3.1.0",
2020
"@types/node": "^14.0.26",
21+
"@types/request": "^2.48.5",
2122
"@types/yargs": "^15.0.5",
2223
"@typescript-eslint/eslint-plugin": "^3.8.0",
2324
"@typescript-eslint/parser": "^3.8.0",
@@ -27,6 +28,7 @@
2728
},
2829
"dependencies": {
2930
"archiver": "^5.0.0",
31+
"request": "^2.88.2",
3032
"tracer": "^1.1.3",
3133
"yargs": "^15.4.1"
3234
}

src/commands/run.ts

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,38 @@
11
import log from '../log';
22
import Archiver from '../utils/archiver';
33
import Uploader from '../utils/uploader';
4+
import Config from '../utils/config';
45

56
interface Arguments {
67
[x: string]: unknown;
7-
p: string | boolean;
8+
cf: string | boolean;
89
}
910

1011
export default class RunProject {
11-
private path = '.';
12-
private archiver: Archiver;
13-
private uploader: Uploader;
12+
private archiver: Archiver | undefined = undefined;
13+
private uploader: Uploader | undefined = undefined;
1414

1515
constructor(argv: Arguments) {
16-
this.archiver = new Archiver({
17-
cypress_path: '.',
18-
});
19-
20-
this.uploader = new Uploader({
21-
cypress_path: '',
22-
});
16+
this.start();
2317
}
2418

2519
public async start(): Promise<void> {
26-
let zipFile: string | undefined;
20+
const config = await Config.getConfig();
21+
const configValidationError = Config.validate(config);
22+
if (configValidationError) {
23+
throw new Error(
24+
`Configuration error: ${configValidationError.join('\n')}`,
25+
);
26+
}
27+
28+
this.archiver = new Archiver(config);
29+
this.uploader = new Uploader(config);
30+
31+
let zipFile: string;
32+
33+
if (!this.archiver || !this.uploader) {
34+
throw new Error(`Invalid state, please try again`);
35+
}
2736

2837
try {
2938
zipFile = await this.archiver.start();
@@ -32,6 +41,12 @@ export default class RunProject {
3241
return;
3342
}
3443

35-
const success = await this.uploader.start();
44+
try {
45+
const success = await this.uploader.start(zipFile);
46+
log.info('got success', success);
47+
} catch (err) {
48+
log.error(err);
49+
return;
50+
}
3651
}
3752
}

src/index.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as yargs from 'yargs';
22
import InitProject from './commands/init';
3+
import RunProject from './commands/run';
34

45
process.removeAllListeners('warning');
56

@@ -24,6 +25,22 @@ yargs
2425

2526
return new InitProject(initArgv);
2627
})
28+
.command('run', 'more info', function (yargs) {
29+
const initArgv = yargs
30+
.usage('usage: $0 run [options]')
31+
.options({
32+
cf: {
33+
alias: 'config-file',
34+
default: 'testingbot.json',
35+
description: 'The path to the testingbot.json config file',
36+
type: 'string',
37+
demand: true,
38+
},
39+
})
40+
.help('help')
41+
.wrap(null).argv;
42+
return new RunProject(initArgv);
43+
})
2744
.alias('h', 'help')
2845
.help('help')
2946
.wrap(null).argv;

src/utils/archiver.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,15 @@ import fs from 'fs';
33
import path from 'path';
44
import os from 'os';
55
import log from './../log';
6+
import { IConfig } from './config';
67

78
const fsPromises = fs.promises;
8-
interface ArchiveSettings {
9-
cypress_path: string;
10-
}
119

1210
export default class Archiver {
13-
private settings: ArchiveSettings;
11+
private config: IConfig;
1412

15-
constructor(settings: ArchiveSettings) {
16-
this.settings = settings;
13+
constructor(config: IConfig) {
14+
this.config = config;
1715
}
1816

1917
public async start(): Promise<string> {
@@ -57,7 +55,7 @@ export default class Archiver {
5755
];
5856
allowedFileTypes.forEach((fileType) => {
5957
archive.glob(`**/*.${fileType}`, {
60-
cwd: this.settings.cypress_path,
58+
cwd: this.config.run_settings.cypress_project_dir,
6159
matchBase: true,
6260
ignore: [
6361
'node_modules/**',
@@ -71,10 +69,6 @@ export default class Archiver {
7169
archive.finalize();
7270
} catch (e) {
7371
reject(e);
74-
} finally {
75-
if (tempZipFile) {
76-
fsPromises.unlink(tempZipFile);
77-
}
7872
}
7973
});
8074
}

src/utils/config.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import fs from 'fs';
2+
3+
const fsPromises = fs.promises;
4+
5+
interface IAuth {
6+
key: string;
7+
secret: string;
8+
}
9+
10+
interface IBrowser {
11+
browserName: string;
12+
platform: string;
13+
versions: string[];
14+
}
15+
16+
interface IRunSettings {
17+
cypress_project_dir: string;
18+
project_name: string;
19+
build_name: string;
20+
parallel_count: number;
21+
npm_dependencies: any;
22+
package_config_options: any;
23+
}
24+
25+
export interface IConfig {
26+
auth: IAuth;
27+
browsers: IBrowser[];
28+
run_settings: IRunSettings;
29+
}
30+
31+
export default {
32+
async getConfig(): Promise<IConfig> {
33+
const configString = await fsPromises.readFile(`testingbot.json`);
34+
const configObject = JSON.parse(configString.toString());
35+
36+
return configObject as IConfig;
37+
},
38+
39+
validate(config: IConfig): string[] {
40+
const errors: string[] = [];
41+
if (config.auth.key === '' || config.auth.key === '<Your TestingBot key>') {
42+
errors.push(
43+
`Please add a valid TestingBot key in the testingbot.json file`,
44+
);
45+
}
46+
if (
47+
config.auth.secret === '' ||
48+
config.auth.secret === '<Your TestingBot secret>'
49+
) {
50+
errors.push(
51+
`Please add a valid TestingBot scret in the testingbot.json file`,
52+
);
53+
}
54+
55+
return errors;
56+
},
57+
};

src/utils/uploader.ts

Lines changed: 34 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,48 @@
1-
import archiver, { ArchiverError } from 'archiver';
21
import fs from 'fs';
3-
import path from 'path';
4-
import os from 'os';
2+
import request from 'request';
53
import log from './../log';
6-
7-
const fsPromises = fs.promises;
8-
interface UploadSettings {
9-
cypress_path: string;
10-
}
4+
import { IConfig } from './config';
115

126
export default class Uploader {
13-
private settings: UploadSettings;
7+
private config: IConfig;
148

15-
constructor(settings: UploadSettings) {
16-
this.settings = settings;
9+
constructor(config: IConfig) {
10+
this.config = config;
1711
}
1812

19-
public async start(): Promise<string> {
13+
public async start(zipFile: string): Promise<string> {
2014
return new Promise((resolve, reject) => {
21-
let tempZipFile: string | undefined;
22-
23-
try {
24-
tempZipFile = path.join(os.tmpdir(), 'upload.zip');
25-
const output = fs.createWriteStream(tempZipFile);
26-
const archive = archiver('zip', {
27-
zlib: { level: 9 },
28-
});
29-
30-
archive.on('warning', (err: ArchiverError) => {
31-
if (err.code === 'ENOENT') {
32-
log.warn(err);
15+
const requestOptions = {
16+
method: 'POST',
17+
uri: 'https://api.testingbot.com/v1/storage',
18+
auth: {
19+
user: this.config.auth.key,
20+
pass: this.config.auth.secret,
21+
sendImmediately: true,
22+
},
23+
formData: {
24+
file: fs.createReadStream(zipFile),
25+
},
26+
};
27+
28+
request(requestOptions, function (error, response) {
29+
if (error) {
30+
return reject(error);
31+
}
32+
let responseBody = null;
33+
if (response) {
34+
if (response.body && typeof response.body === 'string') {
35+
response.body = JSON.parse(response.body);
36+
}
37+
if (response.statusCode.toString().substring(0, 1) === '2') {
38+
responseBody = response.body;
3339
} else {
34-
reject(err);
40+
return reject(response.body);
3541
}
36-
});
37-
38-
// listen for all archive data to be written
39-
// 'close' event is fired only when a file descriptor is involved
40-
output.on('close', () => {
41-
resolve(tempZipFile);
42-
});
43-
44-
archive.on('error', (err: ArchiverError) => {
45-
reject(err);
46-
});
47-
48-
archive.pipe(output);
49-
50-
const allowedFileTypes = [
51-
'js',
52-
'json',
53-
'txt',
54-
'ts',
55-
'feature',
56-
'features',
57-
];
58-
allowedFileTypes.forEach((fileType) => {
59-
archive.glob(`**/*.${fileType}`, {
60-
cwd: this.settings.cypress_path,
61-
matchBase: true,
62-
ignore: [
63-
'node_modules/**',
64-
'package-lock.json',
65-
'package.json',
66-
'testingbot-package.json',
67-
],
68-
});
69-
});
70-
71-
archive.finalize();
72-
} catch (e) {
73-
reject(e);
74-
} finally {
75-
if (tempZipFile) {
76-
fsPromises.unlink(tempZipFile);
7742
}
78-
}
43+
44+
resolve(responseBody);
45+
});
7946
});
8047
}
8148
}

0 commit comments

Comments
 (0)