Skip to content

Commit 49bc3d8

Browse files
authored
Patch update (#3)
* removing debug * validating conn string * modified connStringRegex * updated fileconstants * updated error log * refactor * added comments
1 parent 9f2eeea commit 49bc3d8

File tree

11 files changed

+153
-43
lines changed

11 files changed

+153
-43
lines changed

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,5 +348,3 @@ MigrationBackup/
348348

349349
# Ionide (cross platform F# VS Code tools) working folder
350350
.ionide/
351-
node_modules
352-

lib/Constants.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ exports.PsqlConstants = exports.FirewallConstants = exports.FileConstants = void
44
class FileConstants {
55
}
66
exports.FileConstants = FileConstants;
7-
FileConstants.singleParentDirRegex = /.*(\.sql){1}$/g;
7+
// regex checks that string should end with .sql and if folderPath is present, * should not be included in folderPath
8+
FileConstants.singleParentDirRegex = /^((?!\*\/).)*(\.sql)$/g;
89
class FirewallConstants {
910
}
1011
exports.FirewallConstants = FirewallConstants;
@@ -13,4 +14,7 @@ class PsqlConstants {
1314
}
1415
exports.PsqlConstants = PsqlConstants;
1516
PsqlConstants.SELECT_1 = "SELECT 1";
16-
PsqlConstants.extractPasswordRegex = /(?<key>password)=(?<val>[^\s]*)/g;
17+
// host, port, dbname, user, password must be present in connection string in any order.
18+
PsqlConstants.connectionStringTestRegex = /^(?=.*host(\s)*=(\s)*.+)(?=.*port(\s)*=(\s)*.+)(?=.*dbname(\s)*=(\s)*.+)(?=.*user(\s)*=(\s)*.+)(?=.*password(\s)*=(\s)*.+).+/g;
19+
// extracting password from connection string
20+
PsqlConstants.extractPasswordRegex = /(?<key>password)\s*=\s*(?<val>[^\s]*)/g;

lib/FileListCreator/FileListCreator.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ class FileListCreator {
1212
const singleParentDir = new SingleParentDir_1.default(filePathRegex);
1313
this.fileList = singleParentDir.getFileList();
1414
}
15+
if (!this.fileList) {
16+
throw new Error(`Invalid file path. File path should be of the format <file>.sql, <folder>/<regex>.sql, <folder1>/<folder2>/<folder3>/<regex>.sql`);
17+
}
1518
return this.fileList;
1619
}
1720
}

lib/Utils/ActionInputs.js

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ const Constants_1 = require("../Constants");
2525
class ActionInputs {
2626
constructor() {
2727
this._serverName = core.getInput('server-name', { required: true });
28-
console.log(`this.servername: ${this._serverName}`);
29-
this._connectionString = core.getInput('connection-string', { required: true }).split("psql")[1].trim();
28+
this._connectionString = core.getInput('connection-string', { required: true });
3029
this._plsqlFile = core.getInput('plsql-file', { required: true });
3130
this._args = core.getInput('arguments');
3231
this.parseConnectionString();
@@ -38,20 +37,18 @@ class ActionInputs {
3837
return this.actionInputs;
3938
}
4039
parseConnectionString() {
40+
this._connectionString = this._connectionString.replace('psql', "").replace(/["]+/g, '').trim();
41+
if (!this.validateConnectionString()) {
42+
throw new Error(`Please provide a valid connection string. A valid connection string is a series of keyword/value pairs separated by space. Spaces around the equal sign are optional. To write an empty value, or a value containing spaces, surround it with single quotes, e.g., keyword = 'a value'. Single quotes and backslashes within the value must be escaped with a backslash`);
43+
}
4144
const password = this.getPassword();
4245
if (!password) {
4346
throw new Error(`Password not found in connection string`);
4447
}
4548
core.setSecret(password);
4649
}
47-
get connectionString() {
48-
return this._connectionString;
49-
}
50-
get plsqlFile() {
51-
return this._plsqlFile;
52-
}
53-
get args() {
54-
return this._args;
50+
validateConnectionString() {
51+
return Constants_1.PsqlConstants.connectionStringTestRegex.test(this.connectionString);
5552
}
5653
getPassword() {
5754
let password = '';
@@ -64,6 +61,15 @@ class ActionInputs {
6461
return password;
6562
}
6663
;
64+
get connectionString() {
65+
return this._connectionString;
66+
}
67+
get plsqlFile() {
68+
return this._plsqlFile;
69+
}
70+
get args() {
71+
return this._args;
72+
}
6773
get serverName() {
6874
return this._serverName;
6975
}

src/Constants.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export class FileConstants {
2-
static readonly singleParentDirRegex = /.*(\.sql){1}$/g;
2+
// regex checks that string should end with .sql and if folderPath is present, * should not be included in folderPath
3+
static readonly singleParentDirRegex = /^((?!\*\/).)*(\.sql)$/g;
34
}
45

56
export class FirewallConstants {
@@ -8,5 +9,8 @@ export class FirewallConstants {
89

910
export class PsqlConstants {
1011
static readonly SELECT_1 = "SELECT 1";
11-
static readonly extractPasswordRegex = /(?<key>password)=(?<val>[^\s]*)/g;
12+
// host, port, dbname, user, password must be present in connection string in any order.
13+
static readonly connectionStringTestRegex = /^(?=.*host(\s)*=(\s)*.+)(?=.*port(\s)*=(\s)*.+)(?=.*dbname(\s)*=(\s)*.+)(?=.*user(\s)*=(\s)*.+)(?=.*password(\s)*=(\s)*.+).+/g;
14+
// extracting password from connection string
15+
static readonly extractPasswordRegex = /(?<key>password)\s*=\s*(?<val>[^\s]*)/g;
1216
}

src/FileListCreator/FileListCreator.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ export class FileListCreator {
1414
const singleParentDir = new SingleParentDir(filePathRegex);
1515
this.fileList = singleParentDir.getFileList();
1616
}
17+
if(!this.fileList) {
18+
throw new Error(`Invalid file path. File path should be of the format <file>.sql, <folder>/<regex>.sql, <folder1>/<folder2>/<folder3>/<regex>.sql`);
19+
}
1720
return this.fileList;
1821
}
1922

src/Utils/ActionInputs.ts

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ export class ActionInputs {
1010

1111
constructor() {
1212
this._serverName = core.getInput('server-name', { required: true });
13-
console.log(`this.servername: ${this._serverName}`)
14-
this._connectionString = core.getInput('connection-string', { required: true }).split("psql")[1].trim();
13+
this._connectionString = core.getInput('connection-string', { required: true });
1514
this._plsqlFile = core.getInput('plsql-file', { required: true });
1615
this._args = core.getInput('arguments');
1716
this.parseConnectionString();
@@ -25,25 +24,21 @@ export class ActionInputs {
2524
}
2625

2726
private parseConnectionString() {
27+
this._connectionString = this._connectionString.replace('psql', "").replace(/["]+/g, '').trim();
28+
if (!this.validateConnectionString()) {
29+
throw new Error(`Please provide a valid connection string. A valid connection string is a series of keyword/value pairs separated by space. Spaces around the equal sign are optional. To write an empty value, or a value containing spaces, surround it with single quotes, e.g., keyword = 'a value'. Single quotes and backslashes within the value must be escaped with a backslash`);
30+
}
2831
const password = this.getPassword();
2932
if (!password) {
3033
throw new Error(`Password not found in connection string`);
3134
}
3235
core.setSecret(password);
3336
}
34-
35-
public get connectionString() {
36-
return this._connectionString;
37-
}
3837

39-
public get plsqlFile() {
40-
return this._plsqlFile;
38+
private validateConnectionString(): boolean {
39+
return PsqlConstants.connectionStringTestRegex.test(this.connectionString);
4140
}
42-
43-
public get args() {
44-
return this._args;
45-
}
46-
41+
4742
private getPassword() {
4843
let password = '';
4944
let matchingGroup = PsqlConstants.extractPasswordRegex.exec(this.connectionString);
@@ -54,6 +49,18 @@ export class ActionInputs {
5449
}
5550
return password;
5651
};
52+
53+
public get connectionString() {
54+
return this._connectionString;
55+
}
56+
57+
public get plsqlFile() {
58+
return this._plsqlFile;
59+
}
60+
61+
public get args() {
62+
return this._args;
63+
}
5764

5865
public get serverName() {
5966
return this._serverName;

src/Utils/FirewallUtils/FirewallManager.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as core from '@actions/core';
22
import AzurePSQLResourceManager from './ResourceManager';
3-
import PsqlUtils from '../PsqlUtils/PsqlUtils';
43

54
export default class FirewallManager {
65
private _firewallRule: any;

src/__tests__/FileListCreator/FileListCreator.test.ts

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,39 @@
11
import { FileListCreator } from "../../FileListCreator/FileListCreator";
2-
import {FileConstants } from "../../Constants";
2+
import SingleParentDir from "../../FileListCreator/SingleParentDir";
3+
4+
jest.mock('../../FileListCreator/SingleParentDir');
35

46
const singleFile = "1.sql";
57
const multipleFiles = "*.sql";
68
const filesInsideFolder = "x/y/*_db.sql";
79
const regexToFail = "x/*/";
10+
const notSqlFile = "x/*.txt";
811

912
describe('Testing fileListCreator', () => {
1013
let getFileListSpy: any;
1114

1215
beforeAll( () => {
13-
getFileListSpy = jest.spyOn(FileListCreator, 'getFileList');
14-
getFileListSpy.mockImplementation((filePathRegex: string) => {
15-
let matchesFilePath = false;
16-
if (FileConstants.singleParentDirRegex.test(filePathRegex)) {
17-
matchesFilePath = true;
18-
}
19-
return matchesFilePath;
16+
getFileListSpy = SingleParentDir.prototype.getFileList = jest.fn().mockImplementation(() => {
17+
return ['1.sql'];
2018
});
2119
});
2220

21+
afterEach(() => {
22+
jest.clearAllMocks();
23+
});
24+
2325
test('getFileList should pass', () => {
24-
expect(getFileListSpy(singleFile)).toBeTruthy;
25-
expect(getFileListSpy(multipleFiles)).toBeTruthy;
26-
expect(getFileListSpy(filesInsideFolder)).toBeTruthy;
26+
expect(FileListCreator.getFileList(singleFile)).toMatchObject(['1.sql']);
27+
expect(FileListCreator.getFileList(multipleFiles)).toMatchObject(['1.sql']);
28+
expect(FileListCreator.getFileList(filesInsideFolder)).toMatchObject(['1.sql']);
29+
30+
expect(getFileListSpy).toHaveBeenCalled();
2731
});
2832

2933
test('getFileList should fail', () => {
30-
expect(getFileListSpy(regexToFail)).toBeFalsy;
34+
expect(FileListCreator.getFileList.bind(regexToFail)).toThrow();
35+
expect(FileListCreator.getFileList.bind(notSqlFile)).toThrow();
36+
expect(getFileListSpy).not.toHaveBeenCalled();
3137
});
3238

3339
});
34-
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import SingleParentDir from "../../FileListCreator/SingleParentDir";
2+
import { FileList } from "../../FileListCreator/FileListCreator";
3+
import { glob } from "glob";
4+
import path from "path";
5+
6+
jest.mock("glob");
7+
8+
let OLD_ENV: any;
9+
const filePathRegex = "1.sql";
10+
let singleParentDir: FileList;
11+
let globSpy: any;
12+
let getFileListSpy: any;
13+
14+
describe('Testing single parent dir', () => {
15+
beforeAll(() => {
16+
OLD_ENV = process.env.GITHUB_WORKSPACE;
17+
globSpy = glob.sync = jest.fn().mockImplementation(() => {
18+
return ['1.sql'];
19+
});
20+
getFileListSpy = jest.spyOn(SingleParentDir.prototype, 'getFileList');
21+
singleParentDir = new SingleParentDir(filePathRegex);
22+
});
23+
24+
afterEach(() => {
25+
jest.clearAllMocks();
26+
});
27+
28+
afterAll(() => {
29+
process.env.GITHUB_WORKSPACE = OLD_ENV;
30+
});
31+
32+
test('getFileList should return list of files', () => {
33+
process.env.GITHUB_WORKSPACE = "gh-workspace";
34+
singleParentDir.getFileList();
35+
36+
expect(globSpy).toHaveBeenCalled();
37+
expect(getFileListSpy).toHaveBeenCalled();
38+
expect(getFileListSpy).toReturnWith([path.join(process.env.GITHUB_WORKSPACE, filePathRegex)]);
39+
});
40+
41+
});

0 commit comments

Comments
 (0)