Compare commits

...

2 Commits

Author SHA1 Message Date
guidohollander 41ece8d1b9 switch, update, flyway support
3 years ago
guidohollander f1adb7e93b shared update method for internals and externals
3 years ago

@ -0,0 +1,29 @@
{
"paths": {
"flywayPath": "c:/fw/flyway",
"componentMigrationsFolder": "_CONTINUOUS_DELIVERY/DATABASE_MIGRATIONS/",
"implementationMigrationsFolder": "_GENERAL/DATABASE_MIGRATIONS/"
},
"exclusions": [
".metadata",
"TEST",
"com.bearingpoint.ird.anguilla.remoting_connector",
"console-1.0-dev.jar",
"migrations.bat",
"etc"
],
"implementations": [
{
"name": "MTS_ANGUILLA",
"functionalName": "MTS Anguilla",
"customer": "ANGUILLA ",
"customerCode": "aia_mts",
"path": "D:\\repo\\aia_mts_trunk\\",
"class": "MxS",
"baseUrl": "https://svn.hollanderconsulting.nl",
"url": "/svn/MTS_ANGUILLA/trunk",
"dbConnectionString": "jdbc:sqlserver://localhost:1433;databaseName=aia_mts;integratedSecurity=true;",
"selected": true
}
]
}

@ -41,7 +41,7 @@
"class": "MxS",
"baseUrl": "https://svn.bearingpointcaribbean.com",
"url": "/svn/MTS_SKN/trunk",
"selected": true
"selected": false
},
{
"name": "ONLINE_SKN",
@ -75,7 +75,7 @@
"class": "MxS",
"baseUrl": "https://svn.bearingpointcaribbean.com",
"url": "/svn/MTS_GRENADA/trunk",
"selected": true
"selected": false
},
{
"name": "ONLINE_GD",

@ -1,24 +1,80 @@
import { DirType } from "./types.js";
import { ExternalComponentResource } from "./ExternalComponentResource.js";
import { svnCheckout, svnInfo } from "./svn.js";
export class AngloResource {
protected _url = "";
protected _baseUrl = "";
protected _fullUrl = "";
protected _bareComponentUrl = "";
protected _repository = "";
protected _repositoryUrl = "";
protected _componentFolder?: string;
protected _implementationUrl = "";
protected _componentName = "";
protected _dirType: DirType = DirType.trunk;
protected _implementationUrl = "";
protected _isMissing?: boolean = undefined;
protected _workingCopyPath = "";
protected _workingCopyResource?: AngloResource = undefined;
protected _repository = "";
protected _repositoryUrl = "";
protected _switchNeeded?: boolean = undefined;
protected _url = "";
protected _version?: string;
protected _componentName = "";
protected _checkoutNumberOfResults = 0;
protected _checkoutRevision = 0;
constructor(baseUrl: string, url: string) {
this.parseUrl(baseUrl, url);
}
public async getWorkingCopyResource(): Promise<AngloResource | undefined> {
if (this._workingCopyPath) {
svnInfo(this._workingCopyPath)
.then((svnResource) => {
const url = svnResource.fullUrl.replace(this._baseUrl, "");
this._isMissing = svnResource.fullUrl === undefined;
if (!this._isMissing) {
this._workingCopyResource = new AngloResource(this._baseUrl, url);
this._switchNeeded =
this.dirTypeAndVersion() !==
this._workingCopyResource.dirTypeAndVersion();
return this._workingCopyResource;
}
})
.catch(async (error) => {
console.log("caught", error);
if (error.message === "NotAWorkingCopy") {
this._isMissing = true;
const checkoutResult = await svnCheckout(
this._baseUrl,
this._url,
this._workingCopyPath
);
this._checkoutNumberOfResults = checkoutResult.numberOfUpdates;
this._checkoutRevision = checkoutResult.revision;
} else {
console.log("other error");
throw error;
}
});
} else {
this._isMissing = true;
// this._switchNeeded = true;
return undefined;
}
}
componentFolder(): string | undefined {
return this._componentFolder;
}
componentName(): string {
return this._componentName;
}
componentNameDecoded(): string {
return decodeURIComponent(this._componentName);
}
componentNameEncoded(): string {
return encodeURIComponent(this._componentName);
}
baseUrl(): string {
return this._baseUrl;
}
@ -28,6 +84,9 @@ export class AngloResource {
implementationUrl(): string {
return this._implementationUrl;
}
private inspectVersion(): void {
// todo
}
repositoryName(): string {
return this._repository;
}
@ -105,7 +164,6 @@ export class AngloResource {
this._componentName = segments[trunkTagBranchIndex + 1];
}
}
this._implementationUrl = segments
.slice(0, trunkTagBranchIndex + (this._version === undefined ? 1 : 2))
.join("/");
@ -127,4 +185,19 @@ export class AngloResource {
return `${segments[0]}.${segments[1]}.${lastSegments.join("-")}`;
}
}
isMissingLocally(): boolean | undefined {
return this._isMissing;
}
localDiffersFromExternal(): boolean | undefined {
return this._switchNeeded;
}
// private getLocalPath(): string {
// if (this instanceof ExternalComponentResource) {
// return 'c:\\ext';
// } else if (this instanceof ImplementationResource) {
// return 'c:\\imp';
// // } else if (this instanceof InternalComponentResource) {
// // return 'c:\\int';
// } else return '';
// }
}

@ -0,0 +1,36 @@
import * as fs from "fs";
import { Settings } from "./types";
export class ConfigurationManager {
private static instance: ConfigurationManager;
private settings: Settings | null = null;
private constructor() {
// private
}
public static getInstance(): ConfigurationManager {
if (!ConfigurationManager.instance) {
ConfigurationManager.instance = new ConfigurationManager();
}
return ConfigurationManager.instance;
}
public loadSettings(filePath: string): void {
const fileData = fs.readFileSync(filePath, "utf-8");
this.settings = JSON.parse(fileData) as Settings;
}
public getSettings(): Settings {
if (!this.settings) {
throw new Error("Settings not loaded. Call loadSettings() first.");
}
return this.settings;
}
}
export function getConfig(): Settings {
const configManager = ConfigurationManager.getInstance();
configManager.loadSettings("./anglo-helper-config.json");
return configManager.getSettings();
}

@ -1,9 +1,26 @@
import * as fs from "fs";
import { AngloVersionedResource } from "./AngloVersionedResource.js";
import { ImplementationResource } from "./ImplementationResource.js";
import { svnUpdate } from "./svn.js";
import { AngloResource } from "./AngloResource.js";
import { getConfig } from "./ConfigurationManager.js";
import {
svnPropGet,
svnSwitchExternal,
svnSwitchWorkingCopy,
svnUpdate,
} from "./svn.js";
import { DirType } from "./types.js";
import { flywayMigrate } from "./flyway.js";
import { unifyPath } from "./parser.js";
const config = getConfig();
export class ExternalComponentResource extends AngloVersionedResource {
public _parentSolutionImplementation: ImplementationResource;
private _updated = false;
private _switchedWorkingCopy = false;
private _flywayed = false;
private _dbScriptFolder = "";
constructor(
baseUrl: string,
@ -12,22 +29,46 @@ export class ExternalComponentResource extends AngloVersionedResource {
) {
super(baseUrl, url);
this._parentSolutionImplementation = parentSolutionImplementation;
this._workingCopyPath =
parentSolutionImplementation._implementationContext && this._componentName
? `${parentSolutionImplementation._implementationContext.path}${this._componentName}`
: "";
this._dbScriptFolder = unifyPath(
`${this._workingCopyPath}/${config.paths.componentMigrationsFolder}`
);
this.getWorkingCopyResource();
}
componentFolder(): string | undefined {
return this._componentFolder;
dbScriptFolder() {
return this._dbScriptFolder;
}
componentName(): string {
return this._componentName;
parentSolutionImplementation(): ImplementationResource {
return this._parentSolutionImplementation;
}
componentNameDecoded(): string {
return decodeURIComponent(this._componentName);
public async flyway(): Promise<boolean> {
try {
if (
this._workingCopyPath &&
this._parentSolutionImplementation._implementationContext
) {
if (fs.existsSync(this._dbScriptFolder)) {
//returns an array of flywayed
this._flywayed = await flywayMigrate(
this._componentName,
this._dbScriptFolder,
this._parentSolutionImplementation._implementationContext
.dbConnectionString
);
return this._flywayed;
} else return false;
} else return false;
} catch (error) {
console.log("Other error", error);
throw error;
}
componentNameEncoded(): string {
return encodeURIComponent(this._componentName);
}
parentSolutionImplementation(): ImplementationResource {
return this._parentSolutionImplementation;
public flywayed(): boolean {
return this._flywayed;
}
public async tag(): Promise<ExternalComponentResource> {
// todo
@ -37,14 +78,52 @@ export class ExternalComponentResource extends AngloVersionedResource {
this._parentSolutionImplementation
);
}
public async update(): Promise<void> {
if (
this._parentSolutionImplementation._implementationContext &&
this._componentName
) {
await svnUpdate(
`${this._parentSolutionImplementation._implementationContext.path}${this._componentName}`
public async switchWorkingCopy(): Promise<boolean> {
try {
if (this._switchNeeded) {
this._switchedWorkingCopy = await svnSwitchWorkingCopy(
this._workingCopyPath,
this.baseUrl(),
this.url()
);
return this._switchedWorkingCopy;
} else return false;
} catch (error) {
console.log("Other error", error);
throw error;
}
}
public switchedWorkingCopy(): boolean {
return this._switchedWorkingCopy;
}
public async switchExternal(
target: ExternalComponentResource
): Promise<boolean> {
await svnSwitchExternal(
this.parentSolutionImplementation().baseUrl(),
this.parentSolutionImplementation().url(),
this.componentName(),
this.implementationUrl(),
target.implementationUrl()
);
return true;
}
public async update(): Promise<boolean> {
try {
if (this._workingCopyPath && this.dirType() != DirType.tags) {
//returns an array of updated
this._updated = await svnUpdate(this._workingCopyPath);
return this._updated;
} else return false;
} catch (error) {
console.log("Other error", error);
throw error;
}
}
public updated(): boolean {
return this._updated;
}
workingCopy(): AngloResource | undefined {
return this._workingCopyResource;
}
}

@ -9,11 +9,13 @@ import { svnList, svnPropGet } from "./svn.js";
import { ExternalComponentResource } from "./ExternalComponentResource.js";
import { AngloVersionedResource } from "./AngloVersionedResource.js";
import { InternalComponentResource } from "./InternalComponentResource.js";
import { AngloResource } from "./AngloResource.js";
import { move } from "./parser.js";
export class ImplementationResource extends AngloVersionedResource {
protected _externalsCollection: ExternalComponentResource[] = [];
protected _internalsCollection: InternalComponentResource[] = [];
public _implementationContext?: TypeSolutionImplementation | undefined;
public _implementationContext: TypeSolutionImplementation | undefined;
constructor(
baseUrl: string,
@ -22,8 +24,17 @@ export class ImplementationResource extends AngloVersionedResource {
) {
super(baseUrl, url);
this._implementationContext = implementationContext;
this._workingCopyPath = implementationContext
? implementationContext.path
: "";
}
public async getCheckoutResults(): Promise<number> {
let sum = 0;
for (const angloResource of AngloResource) {
sum += angloResource._checkoutNumberOfResults;
}
return sum;
}
public async getExternals(): Promise<ExternalComponentResource[]> {
const propGetResult = await svnPropGet(
"svn:externals",
@ -44,12 +55,12 @@ export class ImplementationResource extends AngloVersionedResource {
(project) => !project.componentName().includes("FRONTEND")
);
}
public async getInternals(): Promise<InternalComponentResource[]> {
const svnListResult: InternalComponent[] = await svnList(
this._baseUrl,
this._url
);
svnListResult.forEach((internalComponent: InternalComponent) => {
const thisInternal = new InternalComponentResource(
this._baseUrl,
@ -59,9 +70,18 @@ export class ImplementationResource extends AngloVersionedResource {
this._internalsCollection.push(thisInternal);
});
//move CD folder to last index position
const componentIndex = this._internalsCollection.findIndex(
(object) => object.componentName() === "_CONTINUOUS_DELIVERY"
);
move(
this._internalsCollection as [],
componentIndex,
this._internalsCollection.length - 1
);
return this._internalsCollection;
}
public async deploymentCheck(): Promise<ExternalComponentResource[]> {
if (!this._externalsCollection) {
await this.getExternals();
@ -79,4 +99,83 @@ export class ImplementationResource extends AngloVersionedResource {
this._implementationContext
);
}
public async suf(
doSwitch = false,
doUpdate = false,
doFlyway = false
): Promise<{
switched: AngloResource[];
updated: AngloResource[];
flyway: AngloResource[];
}> {
// switch/update/flyway internals
const internalPromises = this._internalsCollection.map(
async (internalComponentResource: InternalComponentResource) => {
if (doUpdate) await internalComponentResource.update();
if (doFlyway) await internalComponentResource.flyway();
}
);
// switch/update/flyway externals
const externalPromises = this._externalsCollection.map(
async (externalComponentResource: ExternalComponentResource) => {
if (doSwitch) await externalComponentResource.switchWorkingCopy();
if (doUpdate) await externalComponentResource.update();
if (doFlyway) await externalComponentResource.flyway();
}
);
// wait for all switch/update/flyway operations to complete
await Promise.all([...internalPromises, ...externalPromises]);
// filter only switched ones
const switchedExternals = this._externalsCollection.filter(
(externalComponentResource) => {
return externalComponentResource.switchedWorkingCopy();
}
);
// filter only updates ones
const updatedInternals = this._internalsCollection.filter(
(internalComponentResource) => {
return internalComponentResource.updated();
}
);
const updatedExternals = this._externalsCollection.filter(
(externalComponentResource) => {
return externalComponentResource.updated();
}
);
// combine internals and externals as AngloResources for return
const updatedAngloResources: AngloResource[] = [];
for (const internalComponentResource of updatedInternals) {
updatedAngloResources.push(internalComponentResource);
}
for (const externalComponentResource of updatedExternals) {
updatedAngloResources.push(externalComponentResource);
}
// filter only flywayed ones
const flywayInternals = this._internalsCollection.filter(
(internalComponentResource) => {
return internalComponentResource.flywayed();
}
);
const flywayExternals = this._externalsCollection.filter(
(externalComponentResource) => {
return externalComponentResource.flywayed();
}
);
// combine internals and externals as AngloResources for return
const flywayAngloResources: AngloResource[] = [];
for (const internalComponentResource of flywayInternals) {
flywayAngloResources.push(internalComponentResource);
}
for (const externalComponentResource of flywayExternals) {
flywayAngloResources.push(externalComponentResource);
}
return {
switched: switchedExternals,
updated: updatedAngloResources,
flyway: flywayAngloResources,
};
}
}

@ -1,16 +1,16 @@
import * as fs from "fs";
import { DirType, TypeSolutionImplementation } from "./types.js";
import { TypeSolutionImplementation } from "./types.js";
import { InternalComponentResource } from "./InternalComponentResource.js";
import { ImplementationResource } from "./ImplementationResource.js";
import { ExternalComponentResource } from "./ExternalComponentResource.js";
import { getConfig } from "./ConfigurationManager.js";
export class ImplementationResourceReader {
_solutionImplementationsInFile: TypeSolutionImplementation[];
_solutionImplementationCollection: ImplementationResource[] = [];
constructor() {
const json = fs.readFileSync("solutions.json", "utf-8");
this._solutionImplementationsInFile = JSON.parse(json).filter(
const config = getConfig();
this._solutionImplementationsInFile = config.implementations.filter(
(solutionImplementation: TypeSolutionImplementation) => {
return solutionImplementation.selected;
}
@ -50,17 +50,19 @@ export class ImplementationResourceReader {
// );
externals.forEach(
async (externalComponentResource: ExternalComponentResource) => {
externalComponentResource.update();
// await externalComponentResource.getLocalWorkingCopyResource();
// await externalComponentResource.switch();
// await externalComponentResource.update();
}
);
}
if (autoLoadInternals) {
const internals = await thisSolutionImplementation.getInternals();
internals.forEach(
async (internalComponentResource: InternalComponentResource) => {
internalComponentResource.update();
}
);
// internals.forEach(
// async (internalComponentResource: InternalComponentResource) => {
// await internalComponentResource.update();
// }
// );
}
this._solutionImplementationCollection.push(
thisSolutionImplementation

@ -1,9 +1,19 @@
import * as fs from "fs";
import { AngloResource } from "./AngloResource.js";
import { ImplementationResource } from "./ImplementationResource.js";
import { svnUpdate } from "./svn.js";
import { svnSwitchWorkingCopy, svnUpdate } from "./svn.js";
import { DirType } from "./types.js";
import { getConfig } from "./ConfigurationManager.js";
import { flywayMigrate } from "./flyway.js";
import { unifyPath } from "./parser.js";
const config = getConfig();
export class InternalComponentResource extends AngloResource {
public _parentSolutionImplementation: ImplementationResource;
private _updated = false;
private _flywayed = false;
private _dbScriptFolder = "";
constructor(
baseUrl: string,
@ -12,20 +22,59 @@ export class InternalComponentResource extends AngloResource {
) {
super(baseUrl, url);
this._parentSolutionImplementation = parentSolutionImplementation;
this._workingCopyPath =
parentSolutionImplementation._implementationContext && this._componentName
? `${parentSolutionImplementation._implementationContext.path}${this._componentName}`
: "";
this._dbScriptFolder = unifyPath(
`${this._workingCopyPath}/${config.paths.implementationMigrationsFolder}`
);
this.getWorkingCopyResource();
}
public async checkSpecifics(): Promise<boolean> {
// todo
return true;
}
public async update(): Promise<void> {
public async flyway(): Promise<boolean> {
try {
if (
this._workingCopyPath &&
this._parentSolutionImplementation._implementationContext &&
this._componentName
this._componentName === "_CONTINUOUS_DELIVERY"
) {
await svnUpdate(
`${this._parentSolutionImplementation._implementationContext.path}${this._componentName}`
if (fs.existsSync(this._dbScriptFolder)) {
//returns an array of flywayed
this._flywayed = await flywayMigrate(
"__MigrationsHistory",
this._dbScriptFolder,
this._parentSolutionImplementation._implementationContext
.dbConnectionString
);
return this._flywayed;
} else return false;
} else return false;
} catch (error) {
console.log("Other error", error);
throw error;
}
}
public flywayed(): boolean {
return this._flywayed;
}
public updated(): boolean {
return this._updated;
}
public async update(): Promise<boolean> {
try {
if (this._workingCopyPath && this.dirType() != DirType.tags) {
//returns an array of updated
this._updated = await svnUpdate(this._workingCopyPath);
return this._updated;
} else return false;
} catch (error) {
console.log("Other error", error);
throw error;
}
}
parentSolutionImplementation(): ImplementationResource {

@ -1,8 +0,0 @@
[
".metadata",
"TEST",
"com.bearingpoint.ird.anguilla.remoting_connector",
"console-1.0-dev.jar",
"migrations.bat",
"etc"
]

@ -0,0 +1,163 @@
import { exec, ExecException } from "child_process";
import { getConfig } from "./ConfigurationManager.js";
const config = getConfig();
const flywayPath = config.paths.flywayPath;
config.paths.implementationMigrationsFolder;
function execShellCommand(cmd: string): Promise<string> {
return new Promise((resolve, reject) => {
// console.log('cmd', cmd);
exec(
cmd,
{ maxBuffer: 1024 * 500 },
(error: ExecException | null, stdout: string, stderr: string) => {
if (error) {
// Handle known errors
if (error.message.includes("ERROR")) {
reject(error);
} else {
reject(error);
}
}
resolve(stdout || stderr);
}
);
});
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async function flywayCmdWithResponse(
flywayCommand: string,
flywayArgs: string[]
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): Promise<any> {
return new Promise((resolve, reject) => {
const execCommand = `"${flywayPath}" ${flywayCommand} ${flywayArgs.join(
" "
)}`;
execShellCommand(execCommand)
.then((flywayCmdResponse) => {
resolve(flywayCmdResponse);
})
.catch((error) => {
reject(error);
});
});
}
export async function flywayMigrate(
flywayTable: string,
componentScriptFolder: string,
dbConnectionString: string
): Promise<boolean> {
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const flywayMigrateResponse: any = await flywayCmdWithResponse("migrate", [
"-color=always",
`-locations="filesystem:${componentScriptFolder}"`,
'-schemas="migrations"',
`-table="${flywayTable}"`,
`-url=${dbConnectionString}`,
]);
// migrate
if (!flywayMigrateResponse.includes("No migration necessary")) {
return true;
} else return false;
} catch (error) {
console.log(error);
throw error;
}
}
// async function perform(componentEntry) {
// // set default flyway action to migrate
// let flywayAction = 'migrate';
// const dir = anglo.unifyPath(state.workingCopyFolder) + componentEntry.key;
// const dirWithQuotedProjectName =
// anglo.unifyPath(state.workingCopyFolder) +
// JSON.stringify(componentEntry.key);
// // override default when command line option flywayValidateOnly or flywayRepairOnly is set
// if (clargs.argv.flywayValidateOnly) flywayAction = 'validate'; // instead of migrate
// if (clargs.argv.flywayRepairOnly) flywayAction = 'repair'; // instead of migrate
// const flywayDatabaseTable = '__MigrationsHistory';
// const flywayDatabaseSchema = 'migrations';
// if (
// componentEntry.componentContinuousDeliveryFolderFound ||
// componentEntry.generalContinuousDeliveryFolderFound
// ) {
// // in case of flywayReplaceVariables: check for any uncommitted files beforehand, since all potential changes will be reverted when variables are replaced
// const uncommittedChanges = await checkUncommittedChanges(componentEntry);
// if (!uncommittedChanges) {
// let flywayTable;
// let FlywayDir;
// let FlywayDirWithQuotedProjectName;
// let suffix;
// let flywayLocations;
// if (componentEntry.generalContinuousDeliveryFolderFound) {
// flywayTable = JSON.stringify(flywayDatabaseTable);
// suffix = '/_GENERAL/DATABASE_MIGRATIONS/';
// FlywayDir = `${dir}${suffix}`;
// FlywayDirWithQuotedProjectName = `${dirWithQuotedProjectName}/_GENERAL/DATABASE_MIGRATIONS/`;
// flywayLocations = JSON.stringify(`filesystem:${FlywayDir}`);
// } else {
// flywayTable = JSON.stringify(componentEntry.key);
// suffix = '/_CONTINUOUS_DELIVERY/DATABASE_MIGRATIONS/';
// FlywayDir = `${dir}${suffix}`;
// FlywayDirWithQuotedProjectName = `${dirWithQuotedProjectName}/_CONTINUOUS_DELIVERY/DATABASE_MIGRATIONS/`;
// flywayLocations = JSON.stringify(`filesystem:${FlywayDir}`);
// }
// const flywayDatabaseConnectionString = `jdbc:sqlserver://${
// state.profile.flywayDatabaseServer
// }:${state.profile.flywayDatabaseServerPort};databaseName=${
// state.profile.flywayDatabaseName
// };integratedSecurity=${
// state.profile.flywayDatabaseIntegratedSecurity ? 'true' : 'false'
// };`;
// let credentialsString = '';
// if (!state.profile.flywayDatabaseIntegratedSecurity) {
// credentialsString = `-user=${state.profile.flywayDatabaseUsername} -password=${state.profile.flywayDatabasePassword}`;
// }
// const flywayCommand = `"${state.profile.flywayPath}flyway" ${flywayAction} -color=always -locations=${flywayLocations} -schemas=${flywayDatabaseSchema} -table=${flywayTable} -url=${flywayDatabaseConnectionString} ${credentialsString}`;
// await updateVariablesInSqlFiles(componentEntry, FlywayDir);
// let flywayResult = await util.execShellCommand(flywayCommand);
// // flywayResult = flywayResult.replace(/^Database: .*\(Microsoft SQL Server [\d]+\.[\d]+\)/m, '');
// // flywayResult = flywayResult.replace(/^Flyway Community Edition .*/m, '');
// // flywayResult = flywayResult.replace(/^Current version of schema .*/m, '');
// // flywayResult = flywayResult.trim();
// if (flywayResult.includes('No migration necessary')) {
// consoleLog.logThisLine('[F]', 'gray');
// } else {
// consoleLog.logNewLine('', 'white');
// consoleLog.logNewLine(
// '---------------------------------------------------------------------------------------------',
// 'cyan'
// );
// consoleLog.logNewLine(`${flywayCommand}`, 'cyan');
// consoleLog.logNewLine(
// '---------------------------------------------------------------------------------------------',
// 'cyan'
// );
// consoleLog.logNewLine('', 'white');
// anglo.memorable(
// '[F]',
// state.arrFlywayUpdatedCollection,
// componentEntry,
// flywayResult,
// 'green'
// );
// if (state.profile.verbose) {
// consoleLog.logNewLine('', 'white');
// consoleLog.logNewLine('', 'white');
// consoleLog.logNewLine(flywayResult, 'gray');
// }
// }
// await revertChanges(FlywayDirWithQuotedProjectName);
// } else {
// consoleLog.logNewLine('[F] skipped - uncommitted changes found', 'red');
// }
// } else {
// // flyway enabled, but no continuous delivery folder
// }
// }

@ -2,6 +2,8 @@ import { ImplementationResourceReader } from "./ImplementationResourceReader.js"
import { ImplementationResource } from "./ImplementationResource.js";
import { ExternalComponentResource } from "./ExternalComponentResource.js";
import { ExternalComponent } from "./types.js";
import { ConfigurationManager } from "./ConfigurationManager.js";
// import { svnPropGet, svnList, svnGetLatestTag, } from "./svn.js";
// const baseUrl = 'https://svn.bearingpointcaribbean.com';
@ -10,6 +12,7 @@ import { ExternalComponent } from "./types.js";
async function deploymentCheck() {
const reader = new ImplementationResourceReader();
const implementationResources = await reader.load(true, true);
implementationResources.forEach(
async (implementationResource: ImplementationResource) => {
const collectionOfComponentToBeTagged: ExternalComponentResource[] =
@ -19,6 +22,24 @@ async function deploymentCheck() {
);
}
async function sufImplementations() {
const reader = new ImplementationResourceReader();
const implementationResources = await reader.load(true, true);
implementationResources.forEach(
async (implementationResource: ImplementationResource) => {
const implementationSufResults = await implementationResource.suf(
true,
true,
false
);
console.debug("Switched:", implementationSufResults.switched);
console.debug("Updated:", implementationSufResults.updated);
console.debug("Flyway:", implementationSufResults.flyway);
}
);
// console.debug(implementationResources);
}
// async function start() {
// svnList(baseUrl, url)
// .then((listResult) => {
@ -97,4 +118,9 @@ async function deploymentCheck() {
//start2();
//start3();
// start4();
deploymentCheck();
//deploymentCheck();
//updateAllImplementations();
// Example usage:
sufImplementations();

@ -43,6 +43,14 @@ export function parseExternals(
});
}
export function unifyPath(angloPath: string) {
return angloPath.toString().replaceAll("\\", "/");
}
export function move(array: [], from: number, to: number, on = 1) {
// eslint-disable-next-line no-sequences
return array.splice(to, 0, ...array.splice(from, on)), array;
}
// splittedExternals.forEach((entry) => {
// const tidied = anglo.tidyArrayContent(entry);
// // for componentBaseFolder. If domain-specific, keep first 3, else keep first 4 parts

@ -1,6 +1,4 @@
import exclusions from "./data/exclude.json" assert { type: "json" };
import * as fs from "fs";
import { exec } from "child_process";
import { exec, ExecException } from "child_process";
import { parseString } from "xml2js";
import {
SVNList,
@ -8,32 +6,56 @@ import {
SVNProperties,
DirType,
InternalComponent,
SvnResource,
SVNCheckoutResponse,
SVNCheckoutResult,
} from "./types.js";
import { parseExternals } from "./parser.js";
import { getConfig } from "./ConfigurationManager.js";
function execShellCommand(cmd: string) {
return new Promise((resolve) => {
exec(cmd, { maxBuffer: 1024 * 500 }, (error, stdout, stderr) => {
function execShellCommand(cmd: string): Promise<string> {
return new Promise((resolve, reject) => {
exec(
cmd,
{ maxBuffer: 1024 * 500 },
(error: ExecException | null, stdout: string, stderr: string) => {
if (error) {
console.warn(error);
// Handle known errors
if (
error.message.includes("not a working copy") ||
error.message.includes("does not exist") ||
error.message.includes("None of the targets are working copies")
) {
reject(new Error("NotAWorkingCopy"));
} else {
// Reject the promise with unknown errors
console.log("Unknown error occurred", error);
reject(new Error("Unknown error occurred"));
}
}
resolve(stdout || stderr);
});
}
);
});
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async function svnCmdWithResponse(
cmd: string,
baseUrl: string,
url: string,
returnRaw = false
baseUrl?: string,
url?: string,
localPath?: string,
returnXml = true
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): Promise<any> {
return new Promise((resolve, reject) => {
const execCommand = `svn ${cmd} "${baseUrl}${url}" --xml`;
let execCommand = `svn ${cmd} `;
if (baseUrl && url) execCommand += `"${baseUrl}${url}" `;
if (localPath) execCommand += `"${localPath}" `;
if (returnXml) execCommand += `--xml`;
execShellCommand(execCommand)
.then((svnCmdResponse) => {
if (returnXml) {
parseString(
svnCmdResponse as SVNList | SVNProperties,
(err, result) => {
@ -41,15 +63,14 @@ async function svnCmdWithResponse(
reject(err);
return;
}
if (returnRaw) {
resolve(result);
} else {
const json = JSON.stringify(result);
const svnCmdResponseJson = JSON.parse(json);
resolve(svnCmdResponseJson);
}
}
);
} else {
resolve(svnCmdResponse);
}
})
.catch((error) => {
reject(error);
@ -57,16 +78,49 @@ async function svnCmdWithResponse(
});
}
export async function svnCheckout(
baseUrl: string,
url: string,
localPath: string
): Promise<SVNCheckoutResponse> {
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const svnCheckoutResponse: any = await svnCmdWithResponse(
"checkout",
baseUrl,
url,
localPath,
false
);
// checkout
if (svnCheckoutResponse.startsWith("A")) {
const updateRows = svnCheckoutResponse.split(/\r\n/);
const numberOfUpdates = updateRows.length - 3;
const revision = updateRows[updateRows.length - 2].match(/\d+/)?.[0];
return { numberOfUpdates, revision };
} else {
return { numberOfUpdates: 0, revision: 0 };
}
} catch (error) {
console.log(error);
throw error;
}
}
export async function svnList(
baseUrl: string,
url: string
): Promise<InternalComponent[]> {
try {
const svnListResponse: InternalComponent[] = await svnCmdWithResponse(
const config = getConfig();
const exclusions = config.exclusions;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const svnListResponse: any = await svnCmdWithResponse(
"list",
baseUrl,
url,
false
undefined,
true
);
type arrayOfSVNList = {
@ -77,11 +131,6 @@ export async function svnList(
({ name }: arrayOfSVNList) => `${name[0]}`
);
const excludeJson = fs.readFileSync("./dist/data/exclude.json", "utf-8");
const exclude = JSON.parse(excludeJson);
// const parsedExclusions = exclusions;
const filteredInternals = internals.filter(
(internal: string) => !exclusions.includes(internal)
);
@ -93,6 +142,31 @@ export async function svnList(
}
}
export async function svnInfo(
// baseUrl: string,
// url: string,
localPath: string
): Promise<SvnResource> {
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const svnInfoResponse: any = await svnCmdWithResponse(
"info",
undefined,
undefined,
localPath,
true
);
const fullUrl = svnInfoResponse.info.entry[0].url[0];
const revision = svnInfoResponse.info.entry[0].$.revision;
const returnObject: SvnResource = { fullUrl, revision };
return returnObject;
} catch (error) {
console.log(error);
throw error;
}
}
async function svnCmdWithoutResponse(
cmd: string,
localPath: string
@ -102,7 +176,6 @@ async function svnCmdWithoutResponse(
const execCommand = `svn ${cmd} "${localPath}"`;
execShellCommand(execCommand)
.then((svnCmdResponse) => {
console.log(`Performed ${execCommand}`);
resolve(svnCmdResponse);
})
.catch((error) => {
@ -111,16 +184,73 @@ async function svnCmdWithoutResponse(
});
}
export async function svnUpdate(localPath: string): Promise<void> {
export async function svnUpdate(localPath: string): Promise<boolean> {
try {
await svnCmdWithoutResponse("cleanup", localPath);
const updateResponse = await svnCmdWithResponse(
"update",
undefined,
undefined,
localPath,
false
);
return (
!updateResponse.includes("At revision") ||
updateResponse.includes("Updated to")
);
} catch (error) {
console.log(error);
console.log("svnUpdateFailed", error);
throw new Error("svnUpdateFailed");
}
}
export async function svnSwitchWorkingCopy(
localPath: string,
targetBaseUrl: string,
targetUrl: string
): Promise<boolean> {
try {
await svnCmdWithoutResponse("update", localPath);
await svnCmdWithoutResponse("cleanup", localPath);
const switchResponse = await svnCmdWithResponse(
"switch",
targetBaseUrl,
targetUrl,
localPath,
false
);
return (
switchResponse.includes("At revision") ||
switchResponse.includes("Updated to revision")
);
} catch (error) {
console.log(error);
console.log("svnSwitchFailed", error);
throw new Error("svnSwitchFailed");
}
}
export async function svnSwitchExternal(
baseUrl: string,
url: string,
componentName: string, // in tortoise this is called Local path while editing svn:externals definitions
sourceUrl: string,
targetUrl: string
): Promise<boolean> {
try {
// get fresh raw externals
const propGetResult = await svnPropGet("svn:externals", baseUrl, url);
console.log(propGetResult);
// find
// if found
// propGetResult.replace()
// svmuc back as externals
//else throw error
const switchResponse = "";
return (
!switchResponse.includes("At revision") ||
switchResponse.includes("Updated to")
);
} catch (error) {
console.log("svnSwitchFailed", error);
throw new Error("svnSwitchFailed");
}
}
@ -133,6 +263,7 @@ export async function svnPropGet(
`propget ${property}`,
baseUrl,
url,
undefined,
true
);
const rawExternals: string =
@ -145,7 +276,7 @@ export async function svnTagsBranchesList(
baseUrl: string,
url: string, // expects url that has tags and branches
latestOnly = false
): Promise<string[]> {
): Promise<string[] | undefined> {
try {
url = url.replace(/trunk$/, "");
url = url.replace(/tags$/, "");
@ -154,7 +285,9 @@ export async function svnTagsBranchesList(
const svnListResponse: SVNList = await svnCmdWithResponse(
"list",
baseUrl,
url
url,
undefined,
true
);
const regex = /^[0-9.]+$/; // Regular expression for semantic version format
type arrayOfSVNList = {
@ -213,27 +346,27 @@ export async function svnTagsBranchesList(
export async function svnGetLatestTag(
baseUrl: string,
url: string
): Promise<string[]> {
): Promise<string[] | undefined> {
return svnTagsBranchesList(DirType.tags, baseUrl, url, true);
}
export async function svnGetLatestBranch(
baseUrl: string,
url: string
): Promise<string[]> {
): Promise<string[] | undefined> {
return svnTagsBranchesList(DirType.branches, baseUrl, url, true);
}
export async function svnGetTagList(
baseUrl: string,
url: string
): Promise<string[]> {
): Promise<string[] | undefined> {
return svnTagsBranchesList(DirType.tags, baseUrl, url, false);
}
export async function svnGetBranchesList(
baseUrl: string,
url: string
): Promise<string[]> {
): Promise<string[] | undefined> {
return svnTagsBranchesList(DirType.branches, baseUrl, url, false);
}

@ -1,5 +1,15 @@
import { ExternalComponentResource } from "./ExternalComponentResource";
export enum SVNCheckoutResult {
at_revision,
missing,
}
export type SVNCheckoutResponse = {
numberOfUpdates: number;
revision: number;
};
export type SVNProperties = {
properties: {
target: {
@ -39,6 +49,10 @@ export type SVNList = {
};
};
export type ErrorType = {
message: string;
};
export type ExternalComponent = {
original: string;
key: string;
@ -65,16 +79,22 @@ export enum DirType {
trunk = "trunk",
}
export type TypeSolutionImplementation = {
name: string;
functionalName: string;
customer: string;
customerCode: string;
path: string;
class: string;
baseUrl: string;
url: string;
selected: boolean;
// export type TypeSolutionImplementation = {
// name: string;
// functionalName: string;
// customer: string;
// customerCode: string;
// path: string;
// class: string;
// baseUrl: string;
// url: string;
// dbConnectionString: string;
// selected: boolean;
// };
export type SvnResource = {
fullUrl: string;
revision: number;
};
export type ApiExternalsResponse = {
@ -90,3 +110,28 @@ export type ApiExternalsResponse = {
};
};
};
export interface TypeSolutionImplementation {
name: string;
functionalName: string;
customer: string;
customerCode: string;
path: string;
class: string;
baseUrl: string;
url: string;
dbConnectionString: string;
selected: boolean;
}
export interface Paths {
flywayPath: string;
componentMigrationsFolder: string;
implementationMigrationsFolder: string;
}
export interface Settings {
paths: Paths;
exclusions: string[];
implementations: TypeSolutionImplementation[];
}

@ -39,7 +39,7 @@
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
"resolveJsonModule": true /* Enable importing .json files. */,
// "resolveJsonModule": true /* Enable importing .json files. */,
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */

Loading…
Cancel
Save

Powered by TurnKey Linux.