dcdx 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +85 -0
  3. package/assets/jira-data-generator-5.0.0.jar +0 -0
  4. package/assets/mysql-connector-j-8.3.0.jar +0 -0
  5. package/assets/quickreload-5.0.2.jar +0 -0
  6. package/lib/commands/database-mssql.js +2 -0
  7. package/lib/commands/database-mysql.js +2 -0
  8. package/lib/commands/database-postgres.js +2 -0
  9. package/lib/commands/database.js +2 -0
  10. package/lib/commands/profile.js +2 -0
  11. package/lib/commands/run-bamboo.js +2 -0
  12. package/lib/commands/run-bitbucket.js +2 -0
  13. package/lib/commands/run-confluence.js +2 -0
  14. package/lib/commands/run-jira.js +2 -0
  15. package/lib/commands/run.js +2 -0
  16. package/lib/index.js +2 -0
  17. package/lib/types/applications/bamboo.d.ts +16 -0
  18. package/lib/types/applications/base.d.ts +30 -0
  19. package/lib/types/applications/bitbucket.d.ts +15 -0
  20. package/lib/types/applications/confluence.d.ts +15 -0
  21. package/lib/types/applications/jira.d.ts +15 -0
  22. package/lib/types/commands/database-mssql.d.ts +2 -0
  23. package/lib/types/commands/database-mysql.d.ts +2 -0
  24. package/lib/types/commands/database-postgres.d.ts +2 -0
  25. package/lib/types/commands/database.d.ts +2 -0
  26. package/lib/types/commands/profile.d.ts +1 -0
  27. package/lib/types/commands/run-bamboo.d.ts +2 -0
  28. package/lib/types/commands/run-bitbucket.d.ts +2 -0
  29. package/lib/types/commands/run-confluence.d.ts +2 -0
  30. package/lib/types/commands/run-jira.d.ts +2 -0
  31. package/lib/types/commands/run.d.ts +2 -0
  32. package/lib/types/databases/base.d.ts +30 -0
  33. package/lib/types/databases/mssql.d.ts +19 -0
  34. package/lib/types/databases/mysql.d.ts +19 -0
  35. package/lib/types/databases/postgres.d.ts +18 -0
  36. package/lib/types/helpers/assets.d.ts +1 -0
  37. package/lib/types/helpers/licences.d.ts +2 -0
  38. package/lib/types/helpers/network.d.ts +2 -0
  39. package/lib/types/index.d.ts +2 -0
  40. package/lib/types/types/ApplicationOptions.d.ts +10 -0
  41. package/lib/types/types/DatabaseEngine.d.ts +19 -0
  42. package/lib/types/types/DatabaseOptions.d.ts +7 -0
  43. package/lib/types/types/SupportedApplications.d.ts +1 -0
  44. package/lib/types/types/SupportedDatabaseDrivers.d.ts +1 -0
  45. package/lib/types/types/SupportedDatabaseEngines.d.ts +1 -0
  46. package/package.json +72 -0
package/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2024 Collabsoft
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # The Unofficial Atlassian Data Center Plugin Development CLI
2
+
3
+ ## Mission statement
4
+
5
+ The goal of DCDX is to provide with convenience commands to speed up development of Atlassian apps on the various Atlassian Data Center products.
6
+
7
+ ### Sounds great, how does that work?
8
+
9
+ Once installed, the DCDX command-line utility can be used to quickly start one of the following Atlassian Data Center products:
10
+
11
+ - Jira
12
+ - Confluence
13
+ - Bamboo
14
+ - Bitbucket
15
+
16
+ It includes local versions of one of the following supported databases:
17
+
18
+ - PostgreSQL (default)
19
+ - MySQL
20
+ - Microsoft SQL Server
21
+
22
+ It comes with a lot of plumbing that you would otherwise need to do manually, like a pre-installed 72H developer license (except for Bitbucket) and creating the database with appropriate settings.
23
+
24
+ ### How does this compare to the Atlassian SDK?
25
+
26
+ Glad you asked! We want to be absolutely clear that this is in no way endorsed by Atlassian, nor is it meant to replace the Atlassian SDK or AMPS. You can still use the official methods for developming Data Center apps.
27
+
28
+ However, we have found that for us the official SDK is not sufficient. It has not received many updates and has become sluggish. In addition, the default embedded H2 database is marked deprecated and support will be dropped in future versions of Atlassian products. Many host products also do not run well on Apple Silicon when started using the Atlassian SDK.
29
+
30
+ In short: the purpose of the DCDX CLI is not to replace the Atlassian SDK, but provide convenience methods for app developers in the hope that it will speed up their development flow.
31
+
32
+ ## Installation
33
+
34
+ Install DCDX from NPM as a global package:
35
+
36
+ `npm install -g dcdx`
37
+
38
+ You can now output the usage information.
39
+
40
+ `dcdx --help` or `dcdx <command> --help`
41
+
42
+ That's it, you're good to go!
43
+
44
+ ## Quick Start
45
+
46
+ You can start a version of the Atlassian Data Center product with the default databases (PostgreSQL) with a single command:
47
+
48
+ ```
49
+ $ dcdx run:jira
50
+ ```
51
+
52
+ If you wish to select a different database, you can run
53
+
54
+ ```
55
+ $ dcdx run jira -d mssql
56
+ ```
57
+
58
+ ### Prerequisites (the fine print)
59
+
60
+ DCDX is created using NodeJS and specifically designed for a workflow that uses Docker. At this point, the following tools are required:
61
+
62
+ - NodeJS + NPM
63
+ - Docker
64
+ - Docker Compose
65
+
66
+ ## Contributions
67
+
68
+ We're happy to accept any contribution in the form of issue reports and/or PRs.
69
+
70
+ It is recommended to file an issue before starting work on a PR to make sure that we agree to the proposed fix before you start doing any work.
71
+
72
+ ## License & other legal stuff
73
+
74
+ MIT license
75
+ Copyright (c) 2024 Collabsoft
76
+
77
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
78
+
79
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
80
+
81
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
82
+
83
+ ### Important usage notice
84
+
85
+ The packages in this project rely heavily on other 3rd party Open Source projects, install through npm/yarn. These projects all have their own licenses. Although commercial use of Collabsoft packages is permitted under the MIT license, this right is limited to the "original content" created as part of this project. Please make sure you check the licenses of all 3rd party components. Collabsoft cannot be held responsible for non-compliance with 3rd party licenses when using the packages or source code. The use of 3rd party projects is listed in the dependency section of the package.json or inline in the code (when applicable).
Binary file
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{program as e,Option as t}from"commander";import{gracefulExit as o,asyncExitHook as s}from"exit-hook";import{spawn as i}from"child_process";import{upAll as r}from"docker-compose";import{downAll as a,ps as n}from"docker-compose/dist/v2.js";import c from"events";import{dump as d}from"js-yaml";import{cwd as p}from"process";import{Sequelize as l,ConnectionError as h,TimeoutError as m,ConnectionTimedOutError as g,ConnectionRefusedError as S,ConnectionAcquireTimeoutError as u}from"sequelize";const w={name:"shared",driver:"bridge"};class Base extends c{options;sequelize=null;constructor(e){super(),this.options=e}async run(e,t){try{if(!this.sequelize)throw new Error("Database connection does not exist");await this.sequelize.query(e,{logging:t})}catch(t){console.error("An error occurred while trying to run the following SQL query:",e,t),o()}return null}async start(){console.log(`Starting instance of ${this.name} ⏳`),await this.stop(),await this.up(),this.emit(`${this.name}:up`);if(await this.waitUntilReady()){if(console.log(`Database is ready and accepting connections on localhost:${this.options.port} 🗄️`),await this.onDatabaseReady(),this.emit("db:ready"),this.options.logging){const e=await this.getServiceState();e&&await this.showDockerLogs(e.name)}}else console.log(`Failed to start database ${this.name} ⛔`),o(0)}async stop(){await this.down(),this.emit("db:stopped")}async onDatabaseReady(){}getDockerComposeConfig(){return{version:"3.8",services:{db:this.getService()},networks:{shared:w}}}async up(){const e=d(this.getDockerComposeConfig());return r({cwd:p(),configAsString:e,log:!0})}async down(){const e=d(this.getDockerComposeConfig());return a({cwd:p(),configAsString:e,commandOptions:["-v","--remove-orphans","--rmi","local"],log:!0})}async waitUntilReady(){try{const e="mssql"===this.name?"master":this.options.database;return this.sequelize=new l(e,this.options.username,this.options.password,{host:"localhost",port:this.options.port,dialect:this.name.replace("postgresql","postgres"),retry:{max:30,match:[h,m,g,S,u],backoffBase:1e3,backoffExponent:1},logging:!1}),this.sequelize.authenticate().then((()=>!0)).catch((e=>(console.log(e),!1)))}catch(e){return!1}}async getServiceState(){const e=d(this.getDockerComposeConfig());return(await n({configAsString:e,log:!1,commandOptions:["--all"]})).data.services.find((e=>e.name.includes(this.name)))}async showDockerLogs(e){return new Promise(((t,o)=>{const s=i("docker",["logs","-f","-n","5000",e],{cwd:p()});s.stdout.on("data",(e=>{console.log(e.toString("utf-8").trim())})),s.stderr.on("data",(e=>{console.log(e.toString("utf-8").trim())})),s.on("exit",(e=>0===e?t():o(new Error(`Docker exited with code ${e}`))))}))}}const f={port:1433,database:"dcdx",username:"sa",password:"DataCenterDX!",edition:"Developer",version:"2022"};class MSSQL extends Base{name="mssql";driver="com.microsoft.sqlserver.jdbc.SQLServerDriver";options=f;version="2022";get url(){return`jdbc:sqlserver://db:${this.options.port};databaseName=${this.options.database};trustServerCertificate=true`}constructor(e=f){super({...f,...e})}async onDatabaseReady(){await this.run(`CREATE DATABASE ${this.options.database}`),await this.run(`ALTER DATABASE ${this.options.database} COLLATE SQL_Latin1_General_CP1_CS_AS`),await this.run(`ALTER DATABASE ${this.options.database} SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;`)}getService=()=>({image:`mcr.microsoft.com/mssql/server:${this.version}-latest`,ports:[`${this.options.port||1433}:1433`],environment:{ACCEPT_EULA:"y",MSSQL_SA_PASSWORD:this.options.password||"dcdx",MSSQL_PID:this.options.edition},networks:{shared:{aliases:["db","database"]}}})}(async()=>{const o=e.addOption(new t("-v, --version <version>","The version of Microsoft SQL Server").choices(["2017","2019","2022"]).default("2022")).addOption(new t("-e, --edition <edition>","The edition of Microsoft SQL Server").choices(["Developer","Express","Standard","Enterprise","EnterpriseCore"]).default("Developer")).addOption(new t("-p, --port <port>","The port on which the database will be accessible").default("1433")).addOption(new t("-P, --password <password>","The value passed to MSSQL_SA_PASSWORD environment variable. MS SQL Server password policy applies.").default("DataCenterDX!")).parse(process.argv).opts(),i=new MSSQL({version:o.version,edition:o.edition,port:Number(o.port),password:o.password,logging:!0});s((async()=>{console.log(`Stopping ${i.name}... ⏳`),await i.stop(),console.log(`Stopped ${i.name} 💪`)}),{wait:3e4}),await i.start()})(),process.on("SIGINT",(()=>{console.log("Received term signal, trying to stop gracefully 💪"),o()})),setInterval((()=>{}),1<<30);
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{program as e,Option as t}from"commander";import{gracefulExit as o,asyncExitHook as s}from"exit-hook";import{spawn as a}from"child_process";import{upAll as n}from"docker-compose";import{downAll as i,ps as r}from"docker-compose/dist/v2.js";import c from"events";import{dump as d}from"js-yaml";import{cwd as p}from"process";import{Sequelize as l,ConnectionError as m,TimeoutError as h,ConnectionTimedOutError as g,ConnectionRefusedError as u,ConnectionAcquireTimeoutError as w}from"sequelize";const f={name:"shared",driver:"bridge"};class Base extends c{options;sequelize=null;constructor(e){super(),this.options=e}async run(e,t){try{if(!this.sequelize)throw new Error("Database connection does not exist");await this.sequelize.query(e,{logging:t})}catch(t){console.error("An error occurred while trying to run the following SQL query:",e,t),o()}return null}async start(){console.log(`Starting instance of ${this.name} ⏳`),await this.stop(),await this.up(),this.emit(`${this.name}:up`);if(await this.waitUntilReady()){if(console.log(`Database is ready and accepting connections on localhost:${this.options.port} 🗄️`),await this.onDatabaseReady(),this.emit("db:ready"),this.options.logging){const e=await this.getServiceState();e&&await this.showDockerLogs(e.name)}}else console.log(`Failed to start database ${this.name} ⛔`),o(0)}async stop(){await this.down(),this.emit("db:stopped")}async onDatabaseReady(){}getDockerComposeConfig(){return{version:"3.8",services:{db:this.getService()},networks:{shared:f}}}async up(){const e=d(this.getDockerComposeConfig());return n({cwd:p(),configAsString:e,log:!0})}async down(){const e=d(this.getDockerComposeConfig());return i({cwd:p(),configAsString:e,commandOptions:["-v","--remove-orphans","--rmi","local"],log:!0})}async waitUntilReady(){try{const e="mssql"===this.name?"master":this.options.database;return this.sequelize=new l(e,this.options.username,this.options.password,{host:"localhost",port:this.options.port,dialect:this.name.replace("postgresql","postgres"),retry:{max:30,match:[m,h,g,u,w],backoffBase:1e3,backoffExponent:1},logging:!1}),this.sequelize.authenticate().then((()=>!0)).catch((e=>(console.log(e),!1)))}catch(e){return!1}}async getServiceState(){const e=d(this.getDockerComposeConfig());return(await r({configAsString:e,log:!1,commandOptions:["--all"]})).data.services.find((e=>e.name.includes(this.name)))}async showDockerLogs(e){return new Promise(((t,o)=>{const s=a("docker",["logs","-f","-n","5000",e],{cwd:p()});s.stdout.on("data",(e=>{console.log(e.toString("utf-8").trim())})),s.stderr.on("data",(e=>{console.log(e.toString("utf-8").trim())})),s.on("exit",(e=>0===e?t():o(new Error(`Docker exited with code ${e}`))))}))}}const b={port:3306,database:"dcdx",username:"dcdx",password:"dcdx",version:"8.0"};class MySQL extends Base{name="mysql";driver="com.mysql.jdbc.Driver";options=b;version="8.0";get url(){return`jdbc:mysql://db:${this.options.port}/${this.options.database}?sessionVariables=transaction_isolation='READ-COMMITTED'`}constructor(e=b){super({...b,...e})}async onDatabaseReady(){await this.run(`ALTER DATABASE ${this.options.database} CHARACTER SET 'utf8mb4' COLLATE utf8mb4_bin`)}getService=()=>({image:`mysql:${this.version}`,ports:[`${this.options.port||3306}:3306`],environment:{MYSQL_ROOT_PASSWORD:this.options.password||"dcdx",MYSQL_USER:this.options.username||"dcdx",MYSQL_PASSWORD:this.options.password||"dcdx",MYSQL_DATABASE:this.options.database||"dcdx"},command:["--log_bin_trust_function_creators=1"],networks:{shared:{aliases:["db","database"]}}})}(async()=>{const o=e.addOption(new t("-v, --version <version>","The version of Postgres").choices(["8.0","8.3"]).default("8.3")).addOption(new t("-d, --database <database>","The value passed to MYSQL_DATABASE environment variable").default("dcdx")).addOption(new t("-p, --port <port>","The port on which the database will be accessible").default("3306")).addOption(new t("-U, --username <username>","The value passed to MYSQL_USER environment variable").default("dcdx")).addOption(new t("-P, --password <password>","The value passed to MYSQL_PASSWORD environment variable").default("dcdx")).parse(process.argv).opts(),a=new MySQL({version:o.version,database:o.database,port:Number(o.port),username:o.username,password:o.password,logging:!0});s((async()=>{console.log(`Stopping ${a.name}... ⏳`),await a.stop(),console.log(`Stopped ${a.name} 💪`)}),{wait:3e4}),await a.start()})(),process.on("SIGINT",(()=>{console.log("Received term signal, trying to stop gracefully 💪"),o()})),setInterval((()=>{}),1<<30);
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{program as e,Option as o}from"commander";import{gracefulExit as t,asyncExitHook as s}from"exit-hook";import{spawn as a}from"child_process";import{upAll as n}from"docker-compose";import{downAll as r,ps as i}from"docker-compose/dist/v2.js";import c from"events";import{dump as d}from"js-yaml";import{cwd as p}from"process";import{Sequelize as l,ConnectionError as g,TimeoutError as m,ConnectionTimedOutError as h,ConnectionRefusedError as u,ConnectionAcquireTimeoutError as w}from"sequelize";const S={name:"shared",driver:"bridge"};class Base extends c{options;sequelize=null;constructor(e){super(),this.options=e}async run(e,o){try{if(!this.sequelize)throw new Error("Database connection does not exist");await this.sequelize.query(e,{logging:o})}catch(o){console.error("An error occurred while trying to run the following SQL query:",e,o),t()}return null}async start(){console.log(`Starting instance of ${this.name} ⏳`),await this.stop(),await this.up(),this.emit(`${this.name}:up`);if(await this.waitUntilReady()){if(console.log(`Database is ready and accepting connections on localhost:${this.options.port} 🗄️`),await this.onDatabaseReady(),this.emit("db:ready"),this.options.logging){const e=await this.getServiceState();e&&await this.showDockerLogs(e.name)}}else console.log(`Failed to start database ${this.name} ⛔`),t(0)}async stop(){await this.down(),this.emit("db:stopped")}async onDatabaseReady(){}getDockerComposeConfig(){return{version:"3.8",services:{db:this.getService()},networks:{shared:S}}}async up(){const e=d(this.getDockerComposeConfig());return n({cwd:p(),configAsString:e,log:!0})}async down(){const e=d(this.getDockerComposeConfig());return r({cwd:p(),configAsString:e,commandOptions:["-v","--remove-orphans","--rmi","local"],log:!0})}async waitUntilReady(){try{const e="mssql"===this.name?"master":this.options.database;return this.sequelize=new l(e,this.options.username,this.options.password,{host:"localhost",port:this.options.port,dialect:this.name.replace("postgresql","postgres"),retry:{max:30,match:[g,m,h,u,w],backoffBase:1e3,backoffExponent:1},logging:!1}),this.sequelize.authenticate().then((()=>!0)).catch((e=>(console.log(e),!1)))}catch(e){return!1}}async getServiceState(){const e=d(this.getDockerComposeConfig());return(await i({configAsString:e,log:!1,commandOptions:["--all"]})).data.services.find((e=>e.name.includes(this.name)))}async showDockerLogs(e){return new Promise(((o,t)=>{const s=a("docker",["logs","-f","-n","5000",e],{cwd:p()});s.stdout.on("data",(e=>{console.log(e.toString("utf-8").trim())})),s.stderr.on("data",(e=>{console.log(e.toString("utf-8").trim())})),s.on("exit",(e=>0===e?o():t(new Error(`Docker exited with code ${e}`))))}))}}const f={version:"15",database:"dcdx",port:5432,username:"dcdx",password:"dcdx"};class Postgres extends Base{name="postgresql";driver="org.postgresql.Driver";options=f;version="15";get url(){return`jdbc:postgresql://db:${this.options.port}/${this.options.database}`}constructor(e=f){super({...f,...e})}getService=()=>({image:`postgres:${this.version}`,ports:[`${this.options.port||5432}:5432`],environment:{POSTGRES_USER:this.options.username||"dcdx",POSTGRES_PASSWORD:this.options.password||"dcdx",POSTGRES_DB:this.options.database||"dcdx",POSTGRES_HOST_AUTH_METHOD:"md5",POSTGRES_INITDB_ARGS:"--encoding=UTF-8 --lc-collate=C --lc-ctype=C"},networks:{shared:{aliases:["db","database"]}}})}(async()=>{const t=e.addOption(new o("-v, --version <version>","The version of Postgres").choices(["12","13","14","15"]).default("15")).addOption(new o("-d, --database <database>","The value passed to POSTGRES_DB environment variable").default("dcdx")).addOption(new o("-p, --port <port>","The port on which the database will be accessible").default("5432")).addOption(new o("-U, --username <username>","The value passed to POSTGRES_USER environment variable").default("dcdx")).addOption(new o("-P, --password <password>","The value passed to POSTGRES_PASSWORD environment variable").default("dcdx")).parse(process.argv).opts(),a=new Postgres({version:t.version,database:t.database,port:Number(t.port),username:t.username,password:t.password,logging:!0});s((async()=>{console.log(`Stopping ${a.name}... ⏳`),await a.stop(),console.log(`Stopped ${a.name} 💪`)}),{wait:3e4}),await a.start()})(),process.on("SIGINT",(()=>{console.log("Received term signal, trying to stop gracefully 💪"),t()})),setInterval((()=>{}),1<<30);
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{program as a}from"commander";a.name("dcdx database").command("postgresql","Start PostgreSQL",{executableFile:"./database-postgres.js"}).command("mysql","Start MySQL",{executableFile:"./database-mysql.js"}).command("mssql","Start Microsoft SQL Server",{executableFile:"./database-mssql.js"}),a.parse();
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ console.log("Profiles are currently not supported, but are coming soon!");
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{program as t,Option as s}from"commander";import{gracefulExit as o,asyncExitHook as e}from"exit-hook";import a from"axios";import{dirname as i,join as n}from"path";import{spawn as r}from"child_process";import{downAll as c,ps as d,upAll as l}from"docker-compose/dist/v2.js";import p from"events";import{existsSync as h,mkdirSync as m}from"fs";import{dump as u}from"js-yaml";import{homedir as g}from"os";import{cwd as w}from"process";import b from"simple-git";import{upAll as S}from"docker-compose";import{Sequelize as v,ConnectionError as A,TimeoutError as f,ConnectionTimedOutError as y,ConnectionRefusedError as D,ConnectionAcquireTimeoutError as E}from"sequelize";const getFullPath=t=>{const[,s]=process.argv,o=i(s),e=o.substring(0,o.indexOf("dcdx")+4);return n(e,t.replaceAll("../",""))},T="AAAB3w0ODAoPeNp9Ultr2zAYffevEOwtoMR10qYLGJbYWsno7GA7g90eZPlrotWWjCSnzX79FF8IYWkfDPJ3Oedwzvch2zdoWSvkzpF7v5jdLrwpCkiaIc/1POeRMxAasmMNEa3Az2xnHT04gQJquBQhNeB77vQGuzPs3jk5rXIpx5QZfgDfqAaGUtRUOaj4adX+PkpGy+UOhNE+vnGG5laDags9L3mtuToOJF5Pkja5ZorXJwEXHG+pJQdaNvS/cYtLAysBVFfu19ehvxXPQr4IJwV1AGULKzIneBb+8PBd/GWOH6Yf751No9ieaujleYMHKYl8++Fb13VGo1EUZ/hznOBNEofbIFvHEd6mxDb81kQoUH5EZg+op0dEMFmAQrWSf4AZ9HNvTP1rMZnsrLGmpFpzKsZMVpOy28DQbfweo1AiIQ0quDaK540Bi8w1MhKxRhtZWXvHTghn+zLQBvU46Ela1rLZcYEKOEApazvvfKXceiSoYG/kcTXhTUlFG+XVbgKVNHA+gF7BN8t3UuU5sdpRwXUXGnmlVV0CCmRVU3G8Evf5MKUw9vqIFV36tX7moNjfo7CPTxfenZIJErLMSIhX309pvDd8SUgK3smKMpJsknVKBtr26t4D+gd3AC5qMCwCFHOaTWfFvLCLJPft3qktVo3FafmZAhRojb9IAxj8KEqPDQy0stos394SQQ==X02mq",R={name:"shared",driver:"bridge"};let k=class Base extends p{options;sequelize=null;constructor(t){super(),this.options=t}async run(t,s){try{if(!this.sequelize)throw new Error("Database connection does not exist");await this.sequelize.query(t,{logging:s})}catch(s){console.error("An error occurred while trying to run the following SQL query:",t,s),o()}return null}async start(){console.log(`Starting instance of ${this.name} ⏳`),await this.stop(),await this.up(),this.emit(`${this.name}:up`);if(await this.waitUntilReady()){if(console.log(`Database is ready and accepting connections on localhost:${this.options.port} 🗄️`),await this.onDatabaseReady(),this.emit("db:ready"),this.options.logging){const t=await this.getServiceState();t&&await this.showDockerLogs(t.name)}}else console.log(`Failed to start database ${this.name} ⛔`),o(0)}async stop(){await this.down(),this.emit("db:stopped")}async onDatabaseReady(){}getDockerComposeConfig(){return{version:"3.8",services:{db:this.getService()},networks:{shared:R}}}async up(){const t=u(this.getDockerComposeConfig());return S({cwd:w(),configAsString:t,log:!0})}async down(){const t=u(this.getDockerComposeConfig());return c({cwd:w(),configAsString:t,commandOptions:["-v","--remove-orphans","--rmi","local"],log:!0})}async waitUntilReady(){try{const t="mssql"===this.name?"master":this.options.database;return this.sequelize=new v(t,this.options.username,this.options.password,{host:"localhost",port:this.options.port,dialect:this.name.replace("postgresql","postgres"),retry:{max:30,match:[A,f,y,D,E],backoffBase:1e3,backoffExponent:1},logging:!1}),this.sequelize.authenticate().then((()=>!0)).catch((t=>(console.log(t),!1)))}catch(t){return!1}}async getServiceState(){const t=u(this.getDockerComposeConfig());return(await d({configAsString:t,log:!1,commandOptions:["--all"]})).data.services.find((t=>t.name.includes(this.name)))}async showDockerLogs(t){return new Promise(((s,o)=>{const e=r("docker",["logs","-f","-n","5000",t],{cwd:w()});e.stdout.on("data",(t=>{console.log(t.toString("utf-8").trim())})),e.stderr.on("data",(t=>{console.log(t.toString("utf-8").trim())})),e.on("exit",(t=>0===t?s():o(new Error(`Docker exited with code ${t}`))))}))}};const x={port:1433,database:"dcdx",username:"sa",password:"DataCenterDX!",edition:"Developer",version:"2022"};class MSSQL extends k{name="mssql";driver="com.microsoft.sqlserver.jdbc.SQLServerDriver";options=x;version="2022";get url(){return`jdbc:sqlserver://db:${this.options.port};databaseName=${this.options.database};trustServerCertificate=true`}constructor(t=x){super({...x,...t})}async onDatabaseReady(){await this.run(`CREATE DATABASE ${this.options.database}`),await this.run(`ALTER DATABASE ${this.options.database} COLLATE SQL_Latin1_General_CP1_CS_AS`),await this.run(`ALTER DATABASE ${this.options.database} SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;`)}getService=()=>({image:`mcr.microsoft.com/mssql/server:${this.version}-latest`,ports:[`${this.options.port||1433}:1433`],environment:{ACCEPT_EULA:"y",MSSQL_SA_PASSWORD:this.options.password||"dcdx",MSSQL_PID:this.options.edition},networks:{shared:{aliases:["db","database"]}}})}const L={port:3306,database:"dcdx",username:"dcdx",password:"dcdx",version:"8.0"};class MySQL extends k{name="mysql";driver="com.mysql.jdbc.Driver";options=L;version="8.0";get url(){return`jdbc:mysql://db:${this.options.port}/${this.options.database}?sessionVariables=transaction_isolation='READ-COMMITTED'`}constructor(t=L){super({...L,...t})}async onDatabaseReady(){await this.run(`ALTER DATABASE ${this.options.database} CHARACTER SET 'utf8mb4' COLLATE utf8mb4_bin`)}getService=()=>({image:`mysql:${this.version}`,ports:[`${this.options.port||3306}:3306`],environment:{MYSQL_ROOT_PASSWORD:this.options.password||"dcdx",MYSQL_USER:this.options.username||"dcdx",MYSQL_PASSWORD:this.options.password||"dcdx",MYSQL_DATABASE:this.options.database||"dcdx"},command:["--log_bin_trust_function_creators=1"],networks:{shared:{aliases:["db","database"]}}})}const O={version:"15",database:"dcdx",port:5432,username:"dcdx",password:"dcdx"};class Postgres extends k{name="postgresql";driver="org.postgresql.Driver";options=O;version="15";get url(){return`jdbc:postgresql://db:${this.options.port}/${this.options.database}`}constructor(t=O){super({...O,...t})}getService=()=>({image:`postgres:${this.version}`,ports:[`${this.options.port||5432}:5432`],environment:{POSTGRES_USER:this.options.username||"dcdx",POSTGRES_PASSWORD:this.options.password||"dcdx",POSTGRES_DB:this.options.database||"dcdx",POSTGRES_HOST_AUTH_METHOD:"md5",POSTGRES_INITDB_ARGS:"--encoding=UTF-8 --lc-collate=C --lc-ctype=C"},networks:{shared:{aliases:["db","database"]}}})}const _=n(g(),".dcdx");class Base extends p{options;constructor(t){super(),this.options=t}get baseUrl(){const t=`http://localhost:${this.options.port}`;return this.options.contextPath?`${t}/${this.options.contextPath}`:t}getDatabaseEngine(t){switch(t){case"postgresql":return new Postgres;case"mssql":return new MSSQL;case"mysql":return new MySQL}}async start(){await this.stop(),await this.build(this.options.version),await this.database.start(this.name,this.options.version),await this.up()}async stop(){await this.database.stop(),await this.down()}async isApplicationReady(){try{const t=await a.get(`${this.baseUrl}/status`,{validateStatus:()=>!0}).catch((()=>null));if(t&&200===t.status){const{data:s}=t;if("FIRST_RUN"===s.state)return console.log(`The application ${this.name} is ready on ${this.baseUrl} 🎉`),!0}return!1}catch(t){return!1}}getDockerComposeConfig(){return{version:"3.8",services:{[this.name]:this.getService()},networks:{shared:R}}}async up(){const t=this.getDockerComposeConfig(),s=u(t);await l({cwd:w(),configAsString:s,log:!0}),this.emit(`${this.name}:up`);await this.waitUntilReady()?(this.emit(`${this.name}:ready`),await this.tailApplicationLogs()):console.log(`Failed to start ${this.name} ⛔`),o(0)}async down(){const t=u(this.getDockerComposeConfig());await c({cwd:w(),configAsString:t,commandOptions:["-v","--remove-orphans","--rmi","local"],log:!0}),this.emit(`${this.name}:stopped`)}async getServiceState(){const t=u(this.getDockerComposeConfig());return(await d({configAsString:t,log:!1,commandOptions:["--all"]})).data.services.find((t=>t.name.includes(this.name)))}async waitUntilReady(t=0){console.log(`Waiting for ${this.name} to become available... ${t}s`);const s=await this.getServiceState();return!!(s&&s.state.toLowerCase().startsWith("up")&&await this.isApplicationReady())||(t>=300?(console.error(`A timeout occurred while waiting for ${this.name} to become available ⛔`),s&&await this.showDockerLogs(s.name),!1):(await new Promise((t=>setTimeout(t,1e3))),this.waitUntilReady(t+1)))}getDockerRepositoryUrl(){return`https://bitbucket.org/atlassian-docker/docker-${"jira"===this.name?"atlassian-jira":"bamboo"===this.name?`${this.name}-server`:`atlassian-${this.name}-server`}.git`}async build(t){const s=this.getDockerRepositoryUrl(),o=n(_,this.name,"source");h(o)?await b({baseDir:o}).pull({"--recurse-submodule":null}):(m(n(_,this.name),{recursive:!0}),await b().clone(s,o,{"--recurse-submodule":null})),await new Promise(((s,e)=>{const a=r("docker",["build","-t",`dcdx/${this.name}:${t}`,"--build-arg",`${this.name.toUpperCase()}_VERSION=${t}`,"."],{cwd:o});a.stdout.on("data",(t=>{console.log(t.toString("utf-8").trim())})),a.stderr.on("data",(t=>{console.log(t.toString("utf-8").trim())})),a.on("exit",(t=>0===t?s():e(new Error(`Docker exited with code ${t}`))))}))}async tailApplicationLogs(){const t=await this.getServiceState();t&&t.state.toLowerCase().startsWith("up")&&await this.showApplicationLogs(t.name).catch((()=>null))}async showDockerLogs(t){return new Promise(((s,o)=>{const e=r("docker",["logs","-f","-n","5000",t],{cwd:w()});e.stdout.on("data",(t=>{console.log(t.toString("utf-8").trim())})),e.stderr.on("data",(t=>{console.log(t.toString("utf-8").trim())})),e.on("exit",(t=>0===t?s():o(new Error(`Docker exited with code ${t}`))))}))}async showApplicationLogs(t){return new Promise(((s,o)=>{const e=r("docker",["exec","-i",t,"tail","-F","-n","5000",this.logFilePath],{cwd:w()});e.stdout.on("data",(t=>{console.log(t.toString("utf-8").trim())})),e.stderr.on("data",(t=>{console.log(t.toString("utf-8").trim())})),e.on("SIGINT",(()=>s())),e.on("exit",(t=>0===t?s():o(new Error(`Docker exited with code ${t}`))))}))}}class Bamboo extends Base{name="bamboo";database;logFilePath="/var/atlassian/application-data/bamboo/logs/atlassian-bamboo.log";constructor(t){super(t),this.database=this.getDatabaseEngine(t.database)}getService=()=>{const t=this.getVolumes(),s=this.getEnvironmentVariables();return{build:{context:getFullPath("../../assets"),dockerfile_inline:`\nFROM dcdx/${this.name}:${this.options.version}\nCOPY ./quickreload-5.0.2.jar /var/atlassian/application-data/bamboo/shared/plugins/quickreload-5.0.2.jar\nCOPY ./mysql-connector-j-8.3.0.jar /opt/atlassian/bamboo/lib/mysql-connector-j-8.3.0.jar\nRUN chown -R bamboo:bamboo /var/atlassian/application-data/bamboo`},ports:[`${this.options.port||80}:8085`,...this.options.debug?["5005:5005"]:[]],environment:Object.keys(s).length>0?s:void 0,volumes:t.length>0?t:void 0,networks:["shared"]}};async isApplicationReady(){try{const t=await a.get(`${this.baseUrl}/setup/setupGeneralConfiguration.action`,{validateStatus:()=>!0}).catch((()=>null));return 200===t?.status}catch(t){return!1}}getEnvironmentVariables(){return{...this.options.contextPath?{ATL_TOMCAT_CONTEXTPATH:this.options.contextPath}:"",...this.options.debug?{JVM_SUPPORT_RECOMMENDED_ARGS:this.getJVMArgs()}:"",ATL_BAMBOO_ENABLE_UNATTENDED_SETUP:"true",ATL_LICENSE:this.options.license||T,ATL_JDBC_URL:this.database.url,ATL_JDBC_USER:this.database.options.username,ATL_JDBC_PASSWORD:this.database.options.password,ATL_DB_TYPE:`${this.database.name}`}}getJVMArgs(){const t=[];return this.options.debug&&(t.push("-Dupm.plugin.upload.enabled=true"),t.push("-Xdebug"),t.push("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005")),this.options.quickReload&&t.push("-Dquickreload.dirs=/opt/quickreload"),t.join(" ")}getVolumes(){return[...this.options.quickReload?[`${this.options.quickReload}:/opt/quickreload`]:""]}}(async()=>{const o=t.addOption(new s("-v, --version <version>","The version of the host application").choices(["9.4.3"]).default("9.4.3")).addOption(new s("-d, --database <name>","The database engine on which the host application will run").choices(["postgresql","mysql","mssql"]).default("postgresql")).addOption(new s("-p, --port <port>","The HTTP port on which the host application will be accessible").default("80")).addOption(new s("-c, --contextPath <contextPath>","The context path on which the host application will be accessible")).addOption(new s("-qr, --quickReload <path_to_watch>","Add support for QuickReload and add the provided path to the watch list")).addOption(new s("--debug","Add support for JVM debugger on port 5005")).parse(process.argv).opts(),a=new Bamboo({version:o.version,database:o.database,port:Number(o.port),contextPath:o.contextPath,quickReload:o.qr,debug:o.debug});e((async()=>{console.log(`Stopping ${a.name}... ⏳`),await a.stop(),console.log(`Stopped ${a.name} 💪`)}),{wait:3e4}),await a.start()})(),process.on("SIGINT",(()=>{console.log("Received term signal, trying to stop gracefully 💪"),o()}));
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{program as t,Option as s}from"commander";import{gracefulExit as e,asyncExitHook as o}from"exit-hook";import{dirname as a,join as i}from"path";import n from"axios";import{spawn as r}from"child_process";import{downAll as c,ps as d,upAll as l}from"docker-compose/dist/v2.js";import p from"events";import{existsSync as h,mkdirSync as u}from"fs";import{dump as m}from"js-yaml";import{homedir as g}from"os";import{cwd as b}from"process";import w from"simple-git";import{upAll as S}from"docker-compose";import{Sequelize as v,ConnectionError as f,TimeoutError as A,ConnectionTimedOutError as k,ConnectionRefusedError as R,ConnectionAcquireTimeoutError as y}from"sequelize";const getFullPath=t=>{const[,s]=process.argv,e=a(s),o=e.substring(0,e.indexOf("dcdx")+4);return i(o,t.replaceAll("../",""))},D="AAABmg0ODAoPeNp9Ul1v0zAUfc+vsMRbJadJtjGpUiS2JJRONOlaB4SAB9e9W0xTu7JvCv33eImDOoR4vefe4/PhN59hR5bckPiWRNezKJ5FCZkvGUmiJA4yrZALLPkBUrHXotEnu5eBRW6b8KMUoCyw8xH6BVZs2KKce3TJpUJQXAkofh2lOeccIV1dfRhJC7fRXrJuwJzALPL0/qF+pI9XGaPz+uGGspvbkdRx8Awcr0nRdOCnlXnmSlqOUqv0DltureTKg6vOiIZb6J9PoviaRm9pHHs0M9Cf/Rv1Dv/SP5lMyorR99WartZVXmdsUZW03hQOSHtCF+n2TLAB4hlIoYTegSFHo3+AQPK1QTx+m02nzzrko+JQ6MO0HS4oDBffQ5JrojSSnbRo5LZDcMzSEtREdBb1AYwNRzsXff0JgjCwLjG/4mB5giE+JzhbF3esyOn9lxf1F2145a6OWu2V/qmC/2dVdoctmOqptk5PGid+XJx42w3NPPHWQuD9fXJbL8PktfLhU2Av+N2rYMY6uUEFpncY/AYCgfFAMCwCFHzkBlkGH/vRdTeeBSfUMzUDb4W2AhQyM893WPg2Q8oQAYRdBSyKeVUdog==X02jr",C={name:"shared",driver:"bridge"};let E=class Base extends p{options;sequelize=null;constructor(t){super(),this.options=t}async run(t,s){try{if(!this.sequelize)throw new Error("Database connection does not exist");await this.sequelize.query(t,{logging:s})}catch(s){console.error("An error occurred while trying to run the following SQL query:",t,s),e()}return null}async start(){console.log(`Starting instance of ${this.name} ⏳`),await this.stop(),await this.up(),this.emit(`${this.name}:up`);if(await this.waitUntilReady()){if(console.log(`Database is ready and accepting connections on localhost:${this.options.port} 🗄️`),await this.onDatabaseReady(),this.emit("db:ready"),this.options.logging){const t=await this.getServiceState();t&&await this.showDockerLogs(t.name)}}else console.log(`Failed to start database ${this.name} ⛔`),e(0)}async stop(){await this.down(),this.emit("db:stopped")}async onDatabaseReady(){}getDockerComposeConfig(){return{version:"3.8",services:{db:this.getService()},networks:{shared:C}}}async up(){const t=m(this.getDockerComposeConfig());return S({cwd:b(),configAsString:t,log:!0})}async down(){const t=m(this.getDockerComposeConfig());return c({cwd:b(),configAsString:t,commandOptions:["-v","--remove-orphans","--rmi","local"],log:!0})}async waitUntilReady(){try{const t="mssql"===this.name?"master":this.options.database;return this.sequelize=new v(t,this.options.username,this.options.password,{host:"localhost",port:this.options.port,dialect:this.name.replace("postgresql","postgres"),retry:{max:30,match:[f,A,k,R,y],backoffBase:1e3,backoffExponent:1},logging:!1}),this.sequelize.authenticate().then((()=>!0)).catch((t=>(console.log(t),!1)))}catch(t){return!1}}async getServiceState(){const t=m(this.getDockerComposeConfig());return(await d({configAsString:t,log:!1,commandOptions:["--all"]})).data.services.find((t=>t.name.includes(this.name)))}async showDockerLogs(t){return new Promise(((s,e)=>{const o=r("docker",["logs","-f","-n","5000",t],{cwd:b()});o.stdout.on("data",(t=>{console.log(t.toString("utf-8").trim())})),o.stderr.on("data",(t=>{console.log(t.toString("utf-8").trim())})),o.on("exit",(t=>0===t?s():e(new Error(`Docker exited with code ${t}`))))}))}};const $={port:1433,database:"dcdx",username:"sa",password:"DataCenterDX!",edition:"Developer",version:"2022"};class MSSQL extends E{name="mssql";driver="com.microsoft.sqlserver.jdbc.SQLServerDriver";options=$;version="2022";get url(){return`jdbc:sqlserver://db:${this.options.port};databaseName=${this.options.database};trustServerCertificate=true`}constructor(t=$){super({...$,...t})}async onDatabaseReady(){await this.run(`CREATE DATABASE ${this.options.database}`),await this.run(`ALTER DATABASE ${this.options.database} COLLATE SQL_Latin1_General_CP1_CS_AS`),await this.run(`ALTER DATABASE ${this.options.database} SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;`)}getService=()=>({image:`mcr.microsoft.com/mssql/server:${this.version}-latest`,ports:[`${this.options.port||1433}:1433`],environment:{ACCEPT_EULA:"y",MSSQL_SA_PASSWORD:this.options.password||"dcdx",MSSQL_PID:this.options.edition},networks:{shared:{aliases:["db","database"]}}})}const O={port:3306,database:"dcdx",username:"dcdx",password:"dcdx",version:"8.0"};class MySQL extends E{name="mysql";driver="com.mysql.jdbc.Driver";options=O;version="8.0";get url(){return`jdbc:mysql://db:${this.options.port}/${this.options.database}?sessionVariables=transaction_isolation='READ-COMMITTED'`}constructor(t=O){super({...O,...t})}async onDatabaseReady(){await this.run(`ALTER DATABASE ${this.options.database} CHARACTER SET 'utf8mb4' COLLATE utf8mb4_bin`)}getService=()=>({image:`mysql:${this.version}`,ports:[`${this.options.port||3306}:3306`],environment:{MYSQL_ROOT_PASSWORD:this.options.password||"dcdx",MYSQL_USER:this.options.username||"dcdx",MYSQL_PASSWORD:this.options.password||"dcdx",MYSQL_DATABASE:this.options.database||"dcdx"},command:["--log_bin_trust_function_creators=1"],networks:{shared:{aliases:["db","database"]}}})}const T={version:"15",database:"dcdx",port:5432,username:"dcdx",password:"dcdx"};class Postgres extends E{name="postgresql";driver="org.postgresql.Driver";options=T;version="15";get url(){return`jdbc:postgresql://db:${this.options.port}/${this.options.database}`}constructor(t=T){super({...T,...t})}getService=()=>({image:`postgres:${this.version}`,ports:[`${this.options.port||5432}:5432`],environment:{POSTGRES_USER:this.options.username||"dcdx",POSTGRES_PASSWORD:this.options.password||"dcdx",POSTGRES_DB:this.options.database||"dcdx",POSTGRES_HOST_AUTH_METHOD:"md5",POSTGRES_INITDB_ARGS:"--encoding=UTF-8 --lc-collate=C --lc-ctype=C"},networks:{shared:{aliases:["db","database"]}}})}const x=i(g(),".dcdx");class Base extends p{options;constructor(t){super(),this.options=t}get baseUrl(){const t=`http://localhost:${this.options.port}`;return this.options.contextPath?`${t}/${this.options.contextPath}`:t}getDatabaseEngine(t){switch(t){case"postgresql":return new Postgres;case"mssql":return new MSSQL;case"mysql":return new MySQL}}async start(){await this.stop(),await this.build(this.options.version),await this.database.start(this.name,this.options.version),await this.up()}async stop(){await this.database.stop(),await this.down()}async isApplicationReady(){try{const t=await n.get(`${this.baseUrl}/status`,{validateStatus:()=>!0}).catch((()=>null));if(t&&200===t.status){const{data:s}=t;if("FIRST_RUN"===s.state)return console.log(`The application ${this.name} is ready on ${this.baseUrl} 🎉`),!0}return!1}catch(t){return!1}}getDockerComposeConfig(){return{version:"3.8",services:{[this.name]:this.getService()},networks:{shared:C}}}async up(){const t=this.getDockerComposeConfig(),s=m(t);await l({cwd:b(),configAsString:s,log:!0}),this.emit(`${this.name}:up`);await this.waitUntilReady()?(this.emit(`${this.name}:ready`),await this.tailApplicationLogs()):console.log(`Failed to start ${this.name} ⛔`),e(0)}async down(){const t=m(this.getDockerComposeConfig());await c({cwd:b(),configAsString:t,commandOptions:["-v","--remove-orphans","--rmi","local"],log:!0}),this.emit(`${this.name}:stopped`)}async getServiceState(){const t=m(this.getDockerComposeConfig());return(await d({configAsString:t,log:!1,commandOptions:["--all"]})).data.services.find((t=>t.name.includes(this.name)))}async waitUntilReady(t=0){console.log(`Waiting for ${this.name} to become available... ${t}s`);const s=await this.getServiceState();return!!(s&&s.state.toLowerCase().startsWith("up")&&await this.isApplicationReady())||(t>=300?(console.error(`A timeout occurred while waiting for ${this.name} to become available ⛔`),s&&await this.showDockerLogs(s.name),!1):(await new Promise((t=>setTimeout(t,1e3))),this.waitUntilReady(t+1)))}getDockerRepositoryUrl(){return`https://bitbucket.org/atlassian-docker/docker-${"jira"===this.name?"atlassian-jira":"bamboo"===this.name?`${this.name}-server`:`atlassian-${this.name}-server`}.git`}async build(t){const s=this.getDockerRepositoryUrl(),e=i(x,this.name,"source");h(e)?await w({baseDir:e}).pull({"--recurse-submodule":null}):(u(i(x,this.name),{recursive:!0}),await w().clone(s,e,{"--recurse-submodule":null})),await new Promise(((s,o)=>{const a=r("docker",["build","-t",`dcdx/${this.name}:${t}`,"--build-arg",`${this.name.toUpperCase()}_VERSION=${t}`,"."],{cwd:e});a.stdout.on("data",(t=>{console.log(t.toString("utf-8").trim())})),a.stderr.on("data",(t=>{console.log(t.toString("utf-8").trim())})),a.on("exit",(t=>0===t?s():o(new Error(`Docker exited with code ${t}`))))}))}async tailApplicationLogs(){const t=await this.getServiceState();t&&t.state.toLowerCase().startsWith("up")&&await this.showApplicationLogs(t.name).catch((()=>null))}async showDockerLogs(t){return new Promise(((s,e)=>{const o=r("docker",["logs","-f","-n","5000",t],{cwd:b()});o.stdout.on("data",(t=>{console.log(t.toString("utf-8").trim())})),o.stderr.on("data",(t=>{console.log(t.toString("utf-8").trim())})),o.on("exit",(t=>0===t?s():e(new Error(`Docker exited with code ${t}`))))}))}async showApplicationLogs(t){return new Promise(((s,e)=>{const o=r("docker",["exec","-i",t,"tail","-F","-n","5000",this.logFilePath],{cwd:b()});o.stdout.on("data",(t=>{console.log(t.toString("utf-8").trim())})),o.stderr.on("data",(t=>{console.log(t.toString("utf-8").trim())})),o.on("SIGINT",(()=>s())),o.on("exit",(t=>0===t?s():e(new Error(`Docker exited with code ${t}`))))}))}}class Bitbucket extends Base{name="bitbucket";database;logFilePath="/var/atlassian/application-data/bitbucket/log/atlassian-bitbucket.log";constructor(t){super(t),this.database=this.getDatabaseEngine(t.database)}getService=()=>{const t=this.getVolumes(),s=this.getEnvironmentVariables();return{build:{context:getFullPath("../../assets"),dockerfile_inline:`\nFROM dcdx/${this.name}:${this.options.version}\nCOPY ./quickreload-5.0.2.jar /var/atlassian/application-data/bitbucket/plugins/installed-plugins/quickreload-5.0.2.jar\nCOPY ./mysql-connector-j-8.3.0.jar /var/atlassian/application-data/bitbucket/lib/mysql-connector-j-8.3.0.jar\n\nRUN mkdir -p /var/atlassian/application-data/bitbucket/shared; touch /var/atlassian/application-data/bitbucket/shared/bitbucket.properties; echo "setup.license=${this.options.license||D}" >> /var/atlassian/application-data/bitbucket/shared/bitbucket.properties;\n\nRUN chown -R bitbucket:bitbucket /var/atlassian/application-data/bitbucket`},ports:[`${this.options.port||80}:7990`,...this.options.debug?["5005:5005"]:[]],environment:Object.keys(s).length>0?s:void 0,volumes:t.length>0?t:void 0,networks:["shared"]}};getEnvironmentVariables(){return{...this.options.debug?{JVM_SUPPORT_RECOMMENDED_ARGS:this.getJVMArgs()}:"",JDBC_URL:this.database.url,JDBC_USER:this.database.options.username,JDBC_PASSWORD:this.database.options.password,JDBC_DRIVER:`${this.database.driver}`}}getJVMArgs(){const t=[];return this.options.debug&&(t.push("-Dupm.plugin.upload.enabled=true"),t.push("-Xdebug"),t.push("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005")),this.options.quickReload&&t.push("-Dquickreload.dirs=/opt/quickreload"),t.join(" ")}getVolumes(){return[...this.options.quickReload?[`${this.options.quickReload}:/opt/quickreload`]:""]}}(async()=>{const e=t.addOption(new s("-v, --version <version>","The version of the host application").choices(["8.9.0"]).default("8.9.0")).addOption(new s("-d, --database <name>","The database engine on which the host application will run").choices(["postgresql","mysql","mssql"]).default("postgresql")).addOption(new s("-p, --port <port>","The HTTP port on which the host application will be accessible").default("80")).addOption(new s("-qr, --quickReload <path_to_watch>","Add support for QuickReload and add the provided path to the watch list")).addOption(new s("--debug","Add support for JVM debugger on port 5005")).parse(process.argv).opts(),a=new Bitbucket({version:e.version,database:e.database,port:Number(e.port),quickReload:e.qr,debug:e.debug});o((async()=>{console.log(`Stopping ${a.name}... ⏳`),await a.stop(),console.log(`Stopped ${a.name} 💪`)}),{wait:3e4}),await a.start()})(),process.on("SIGINT",(()=>{console.log("Received term signal, trying to stop gracefully 💪"),e()}));
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{program as t,Option as e}from"commander";import{gracefulExit as s,asyncExitHook as o}from"exit-hook";import{dirname as a,join as i}from"path";import n from"axios";import{spawn as r}from"child_process";import{downAll as c,ps as d,upAll as l}from"docker-compose/dist/v2.js";import p from"events";import{existsSync as h,mkdirSync as m}from"fs";import{dump as u}from"js-yaml";import{homedir as g}from"os";import{cwd as w}from"process";import b from"simple-git";import{upAll as S}from"docker-compose";import{Sequelize as f,ConnectionError as A,TimeoutError as v,ConnectionTimedOutError as D,ConnectionRefusedError as y,ConnectionAcquireTimeoutError as T}from"sequelize";const getFullPath=t=>{const[,e]=process.argv,s=a(e),o=s.substring(0,s.indexOf("dcdx")+4);return i(o,t.replaceAll("../",""))},E="AAACzg0ODAoPeNp9VO9v2jAQ/Z6/wtK+IYWGsEKHFGmQmJau/GgIm9iYJhMOYprYke1A4a+fSchGKtqPPvvevXv3zp/6gqLHLEb2HbKsTvNzp9lC98MA2ZbdNKYgdiAGntPDQ2z688HcdH/aM7P5o2kZTzQEJiE4pDAiCTgBngaD0b0RCr5f1S9uHfcUWXSQBzuIeQrCCDlb10mo6A4cJTLQSVlIlzFUggpI8ickMbAVEbI+ypIliPG6R5Il5z4kXEF3A0xJp1Gywa8pFQePKHAmDdt6+A9cJVQEK5yWmhMV8HGZLRWkwrF8PZMgpGPfGh7IUNBUUc6cAKRCcVEYrblAaZxtKEOrsqj8V/US85zxXd+fUGwD70ickRwyf7ARACziqUYo+8Irmt/jUYD9iT+YYmNIKFPACAuvyHIaQEUSHYgz0G8rorgC8rp5qvaEZVp3pt0u8sve3TiTCsSIr0A6llGr1VwfdwPsmb25PjjbVwq2EcZcm6nS6DKX+I3iT1yP/Cy42TBe4FAK0WhZVtu6azYbZeZlB0U2wrpnkQoqq40Uyst67RqB9zU8k64olYeqKnGmNCzWiseOUoKwhLLoK1ExkZISVg95cr3ZN/YqdueSYW649/mdrfJAZOQM3b3b96DRuhVk3261kkFvexwe41UQtJN12u5Gz6GcPT7Pn71H70t69CPcbx/a9rcj3rDuwlk4xprKCA5VN+oJjsaB2R/75sQfezM3GIxH5myKT6PN/QErtDwgFQE6E9VDCLUZtN8F30Ko0K9IqXTRubnZ8HpFlZtzAyYUGb/ryOOIcYVWVCpBl5kCjUwlUhyF2mY80WaoXxdzEhOWe2YsNoRRWWxMt6xX/hH6P5uxF8b3rLJIlz1LpQW95pQPvqfLq0kmwohIeLs2l9PMzfQ48LvvWTbfMY1AXDg9KJDLCV2C9HUMH+CaJfOfudi/v0kIGVswLAIUEMQ9X77gqGBdfH0HIzBaV8NadPUCFBn+RiUA4D+IqVQpTTouLVY66aCGX02121",C={name:"shared",driver:"bridge"};let R=class Base extends p{options;sequelize=null;constructor(t){super(),this.options=t}async run(t,e){try{if(!this.sequelize)throw new Error("Database connection does not exist");await this.sequelize.query(t,{logging:e})}catch(e){console.error("An error occurred while trying to run the following SQL query:",t,e),s()}return null}async start(){console.log(`Starting instance of ${this.name} ⏳`),await this.stop(),await this.up(),this.emit(`${this.name}:up`);if(await this.waitUntilReady()){if(console.log(`Database is ready and accepting connections on localhost:${this.options.port} 🗄️`),await this.onDatabaseReady(),this.emit("db:ready"),this.options.logging){const t=await this.getServiceState();t&&await this.showDockerLogs(t.name)}}else console.log(`Failed to start database ${this.name} ⛔`),s(0)}async stop(){await this.down(),this.emit("db:stopped")}async onDatabaseReady(){}getDockerComposeConfig(){return{version:"3.8",services:{db:this.getService()},networks:{shared:C}}}async up(){const t=u(this.getDockerComposeConfig());return S({cwd:w(),configAsString:t,log:!0})}async down(){const t=u(this.getDockerComposeConfig());return c({cwd:w(),configAsString:t,commandOptions:["-v","--remove-orphans","--rmi","local"],log:!0})}async waitUntilReady(){try{const t="mssql"===this.name?"master":this.options.database;return this.sequelize=new f(t,this.options.username,this.options.password,{host:"localhost",port:this.options.port,dialect:this.name.replace("postgresql","postgres"),retry:{max:30,match:[A,v,D,y,T],backoffBase:1e3,backoffExponent:1},logging:!1}),this.sequelize.authenticate().then((()=>!0)).catch((t=>(console.log(t),!1)))}catch(t){return!1}}async getServiceState(){const t=u(this.getDockerComposeConfig());return(await d({configAsString:t,log:!1,commandOptions:["--all"]})).data.services.find((t=>t.name.includes(this.name)))}async showDockerLogs(t){return new Promise(((e,s)=>{const o=r("docker",["logs","-f","-n","5000",t],{cwd:w()});o.stdout.on("data",(t=>{console.log(t.toString("utf-8").trim())})),o.stderr.on("data",(t=>{console.log(t.toString("utf-8").trim())})),o.on("exit",(t=>0===t?e():s(new Error(`Docker exited with code ${t}`))))}))}};const k={port:1433,database:"dcdx",username:"sa",password:"DataCenterDX!",edition:"Developer",version:"2022"};class MSSQL extends R{name="mssql";driver="com.microsoft.sqlserver.jdbc.SQLServerDriver";options=k;version="2022";get url(){return`jdbc:sqlserver://db:${this.options.port};databaseName=${this.options.database};trustServerCertificate=true`}constructor(t=k){super({...k,...t})}async onDatabaseReady(){await this.run(`CREATE DATABASE ${this.options.database}`),await this.run(`ALTER DATABASE ${this.options.database} COLLATE SQL_Latin1_General_CP1_CS_AS`),await this.run(`ALTER DATABASE ${this.options.database} SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;`)}getService=()=>({image:`mcr.microsoft.com/mssql/server:${this.version}-latest`,ports:[`${this.options.port||1433}:1433`],environment:{ACCEPT_EULA:"y",MSSQL_SA_PASSWORD:this.options.password||"dcdx",MSSQL_PID:this.options.edition},networks:{shared:{aliases:["db","database"]}}})}const x={port:3306,database:"dcdx",username:"dcdx",password:"dcdx",version:"8.0"};class MySQL extends R{name="mysql";driver="com.mysql.jdbc.Driver";options=x;version="8.0";get url(){return`jdbc:mysql://db:${this.options.port}/${this.options.database}?sessionVariables=transaction_isolation='READ-COMMITTED'`}constructor(t=x){super({...x,...t})}async onDatabaseReady(){await this.run(`ALTER DATABASE ${this.options.database} CHARACTER SET 'utf8mb4' COLLATE utf8mb4_bin`)}getService=()=>({image:`mysql:${this.version}`,ports:[`${this.options.port||3306}:3306`],environment:{MYSQL_ROOT_PASSWORD:this.options.password||"dcdx",MYSQL_USER:this.options.username||"dcdx",MYSQL_PASSWORD:this.options.password||"dcdx",MYSQL_DATABASE:this.options.database||"dcdx"},command:["--log_bin_trust_function_creators=1"],networks:{shared:{aliases:["db","database"]}}})}const P={version:"15",database:"dcdx",port:5432,username:"dcdx",password:"dcdx"};class Postgres extends R{name="postgresql";driver="org.postgresql.Driver";options=P;version="15";get url(){return`jdbc:postgresql://db:${this.options.port}/${this.options.database}`}constructor(t=P){super({...P,...t})}getService=()=>({image:`postgres:${this.version}`,ports:[`${this.options.port||5432}:5432`],environment:{POSTGRES_USER:this.options.username||"dcdx",POSTGRES_PASSWORD:this.options.password||"dcdx",POSTGRES_DB:this.options.database||"dcdx",POSTGRES_HOST_AUTH_METHOD:"md5",POSTGRES_INITDB_ARGS:"--encoding=UTF-8 --lc-collate=C --lc-ctype=C"},networks:{shared:{aliases:["db","database"]}}})}const q=i(g(),".dcdx");class Base extends p{options;constructor(t){super(),this.options=t}get baseUrl(){const t=`http://localhost:${this.options.port}`;return this.options.contextPath?`${t}/${this.options.contextPath}`:t}getDatabaseEngine(t){switch(t){case"postgresql":return new Postgres;case"mssql":return new MSSQL;case"mysql":return new MySQL}}async start(){await this.stop(),await this.build(this.options.version),await this.database.start(this.name,this.options.version),await this.up()}async stop(){await this.database.stop(),await this.down()}async isApplicationReady(){try{const t=await n.get(`${this.baseUrl}/status`,{validateStatus:()=>!0}).catch((()=>null));if(t&&200===t.status){const{data:e}=t;if("FIRST_RUN"===e.state)return console.log(`The application ${this.name} is ready on ${this.baseUrl} 🎉`),!0}return!1}catch(t){return!1}}getDockerComposeConfig(){return{version:"3.8",services:{[this.name]:this.getService()},networks:{shared:C}}}async up(){const t=this.getDockerComposeConfig(),e=u(t);await l({cwd:w(),configAsString:e,log:!0}),this.emit(`${this.name}:up`);await this.waitUntilReady()?(this.emit(`${this.name}:ready`),await this.tailApplicationLogs()):console.log(`Failed to start ${this.name} ⛔`),s(0)}async down(){const t=u(this.getDockerComposeConfig());await c({cwd:w(),configAsString:t,commandOptions:["-v","--remove-orphans","--rmi","local"],log:!0}),this.emit(`${this.name}:stopped`)}async getServiceState(){const t=u(this.getDockerComposeConfig());return(await d({configAsString:t,log:!1,commandOptions:["--all"]})).data.services.find((t=>t.name.includes(this.name)))}async waitUntilReady(t=0){console.log(`Waiting for ${this.name} to become available... ${t}s`);const e=await this.getServiceState();return!!(e&&e.state.toLowerCase().startsWith("up")&&await this.isApplicationReady())||(t>=300?(console.error(`A timeout occurred while waiting for ${this.name} to become available ⛔`),e&&await this.showDockerLogs(e.name),!1):(await new Promise((t=>setTimeout(t,1e3))),this.waitUntilReady(t+1)))}getDockerRepositoryUrl(){return`https://bitbucket.org/atlassian-docker/docker-${"jira"===this.name?"atlassian-jira":"bamboo"===this.name?`${this.name}-server`:`atlassian-${this.name}-server`}.git`}async build(t){const e=this.getDockerRepositoryUrl(),s=i(q,this.name,"source");h(s)?await b({baseDir:s}).pull({"--recurse-submodule":null}):(m(i(q,this.name),{recursive:!0}),await b().clone(e,s,{"--recurse-submodule":null})),await new Promise(((e,o)=>{const a=r("docker",["build","-t",`dcdx/${this.name}:${t}`,"--build-arg",`${this.name.toUpperCase()}_VERSION=${t}`,"."],{cwd:s});a.stdout.on("data",(t=>{console.log(t.toString("utf-8").trim())})),a.stderr.on("data",(t=>{console.log(t.toString("utf-8").trim())})),a.on("exit",(t=>0===t?e():o(new Error(`Docker exited with code ${t}`))))}))}async tailApplicationLogs(){const t=await this.getServiceState();t&&t.state.toLowerCase().startsWith("up")&&await this.showApplicationLogs(t.name).catch((()=>null))}async showDockerLogs(t){return new Promise(((e,s)=>{const o=r("docker",["logs","-f","-n","5000",t],{cwd:w()});o.stdout.on("data",(t=>{console.log(t.toString("utf-8").trim())})),o.stderr.on("data",(t=>{console.log(t.toString("utf-8").trim())})),o.on("exit",(t=>0===t?e():s(new Error(`Docker exited with code ${t}`))))}))}async showApplicationLogs(t){return new Promise(((e,s)=>{const o=r("docker",["exec","-i",t,"tail","-F","-n","5000",this.logFilePath],{cwd:w()});o.stdout.on("data",(t=>{console.log(t.toString("utf-8").trim())})),o.stderr.on("data",(t=>{console.log(t.toString("utf-8").trim())})),o.on("SIGINT",(()=>e())),o.on("exit",(t=>0===t?e():s(new Error(`Docker exited with code ${t}`))))}))}}class Confluence extends Base{name="confluence";database;logFilePath="/var/atlassian/application-data/confluence/logs/atlassian-confluence.log";constructor(t){super(t),this.database=this.getDatabaseEngine(t.database)}getService=()=>{const t=this.getVolumes(),e=this.getEnvironmentVariables();return{build:{context:getFullPath("../../assets"),dockerfile_inline:`\nFROM dcdx/${this.name}:${this.options.version}\nCOPY ./quickreload-5.0.2.jar /opt/atlassian/confluence/confluence/WEB-INF/atlassian-bundled-plugins/quickreload-5.0.2.jar\nCOPY ./mysql-connector-j-8.3.0.jar /opt/atlassian/confluence/confluence/WEB-INF/lib/mysql-connector-j-8.3.0.jar\nRUN chown -R confluence:confluence /opt/atlassian/confluence`},ports:[`${this.options.port||80}:8090`,...this.options.debug?["5005:5005"]:[]],environment:Object.keys(e).length>0?e:void 0,volumes:t.length>0?t:void 0,networks:["shared"]}};getEnvironmentVariables(){return{...this.options.contextPath?{ATL_TOMCAT_CONTEXTPATH:this.options.contextPath}:"",...this.options.debug?{JVM_SUPPORT_RECOMMENDED_ARGS:this.getJVMArgs()}:"",ATL_LICENSE_KEY:this.options.license||E,ATL_JDBC_URL:this.database.url,ATL_JDBC_USER:this.database.options.username,ATL_JDBC_PASSWORD:this.database.options.password,ATL_DB_TYPE:`${this.database.name}`}}getJVMArgs(){const t=[];return this.options.debug&&(t.push("-Dupm.plugin.upload.enabled=true"),t.push("-Xdebug"),t.push("-Xrunjdwp:transport=dt_socket,address=*:5005,server=y,suspend=n"),t.push("-Dcom.sun.management.jmxremote.port=9999"),t.push("-Dcom.sun.management.jmxremote.rmi.port=9998"),t.push("-Dcom.sun.management.jmxremote.authenticate=false"),t.push("-Dcom.sun.management.jmxremote.ssl=false")),this.options.quickReload&&t.push("-Dquickreload.dirs=/opt/quickreload"),t.join(" ")}getVolumes(){return[...this.options.quickReload?[`${this.options.quickReload}:/opt/quickreload`]:""]}}(async()=>{const s=t.addOption(new e("-v, --version <version>","The version of the host application").choices(["8.9.0"]).default("8.9.0")).addOption(new e("-d, --database <name>","The database engine on which the host application will run").choices(["postgresql","mysql","mssql"]).default("postgresql")).addOption(new e("-p, --port <port>","The HTTP port on which the host application will be accessible").default("80")).addOption(new e("-c, --contextPath <contextPath>","The context path on which the host application will be accessible")).addOption(new e("-qr, --quickReload <path_to_watch>","Add support for QuickReload and add the provided path to the watch list")).addOption(new e("--debug","Add support for JVM debugger on port 5005")).parse(process.argv).opts(),a=new Confluence({version:s.version,database:s.database,port:Number(s.port),contextPath:s.contextPath,quickReload:s.qr,debug:s.debug});o((async()=>{console.log(`Stopping ${a.name}... ⏳`),await a.stop(),console.log(`Stopped ${a.name} 💪`)}),{wait:3e4}),await a.start()})(),process.on("SIGINT",(()=>{console.log("Received term signal, trying to stop gracefully 💪"),s()}));
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{program as t,Option as s}from"commander";import{gracefulExit as e,asyncExitHook as o}from"exit-hook";import{dirname as a,join as i}from"path";import n from"axios";import{spawn as r}from"child_process";import{downAll as c,ps as d,upAll as l}from"docker-compose/dist/v2.js";import p from"events";import{existsSync as h,mkdirSync as m}from"fs";import{dump as u}from"js-yaml";import{homedir as g}from"os";import{cwd as w}from"process";import b from"simple-git";import{upAll as S}from"docker-compose";import{Sequelize as A,ConnectionError as v,TimeoutError as f,ConnectionTimedOutError as T,ConnectionRefusedError as y,ConnectionAcquireTimeoutError as D}from"sequelize";const getFullPath=t=>{const[,s]=process.argv,e=a(s),o=e.substring(0,e.indexOf("dcdx")+4);return i(o,t.replaceAll("../",""))},E="AAACBA0ODAoPeNp9kl1v2jAUhu/zK460OyQHSLuVIkUaTbwNVBKUhEnbugsTDuA2sSPbgbFfPxOC1i+4yEXO5+vnPR+yGiGSW/CuoXc7vBoMvT4ENAOv5/WctUIUG1lVqNx7nqPQSJfccCl8GmU0mSXjlDpRXS5Qxau5RqV90ncCKQzLTcRK9Eu944Ip/cQ/M1MwrTkTbi5LZ1arfMM0hsyg7/X6A9LvE89z2j3ZvsJmQBBPpzQJxqP7U4r+qbjaN32zG+/baR2dMl6c35ei2qIah/4dvaHkOvzpkU/x5IZ8vbodOI9cMbdSclnnxj38EC1XZscUunYy36JvVI3OxGZmbZXdzwIU5lVJWi90rnjVQGoi70B873GNhPOQO51OFGfkS5yQWRKH8yAbxxGZp9Qm/EChpbGExR7MBqGdAlTkcokK7MMeMTfwa2NM9TDsdtfSfQGnWxw7CB47frsQShDSwJJro/iiNmgncw1GQl5rI0trtetY4sKgYCJ/Y4qVFSR0lNGQ3P04aDxrTKvWOjMXT0LuxCU33txaSiPffuRjr3fsO/mC6og/VmsmuGYN0Ij93TFYcVXunQaaDb4+wJbFd7vg0OI5If53NENtoK2AlVQwGScjSFt5lrjdWymu8WEIgSwtppyzAsLgxRk8P5hG9PMA3bKiPspdsULjJRwX7ukf5/NX7TAtAhUAhQSHz9DgycOX7wcwERMJb3TLGb4CFGkB/xUWSRK3BZLrPF9Rn6ZmrUqJX02oc",R="AAACzg0ODAoPeNp9VO9v2jAQ/Z6/wtK+IYWGsEKHFGmQmJau/GgIm9iYJhMOYprYke1A4a+fSchGKtqPPvvevXv3zp/6gqLHLEb2HbKsTvNzp9lC98MA2ZbdNKYgdiAGntPDQ2z688HcdH/aM7P5o2kZTzQEJiE4pDAiCTgBngaD0b0RCr5f1S9uHfcUWXSQBzuIeQrCCDlb10mo6A4cJTLQSVlIlzFUggpI8ickMbAVEbI+ypIliPG6R5Il5z4kXEF3A0xJp1Gywa8pFQePKHAmDdt6+A9cJVQEK5yWmhMV8HGZLRWkwrF8PZMgpGPfGh7IUNBUUc6cAKRCcVEYrblAaZxtKEOrsqj8V/US85zxXd+fUGwD70ickRwyf7ARACziqUYo+8Irmt/jUYD9iT+YYmNIKFPACAuvyHIaQEUSHYgz0G8rorgC8rp5qvaEZVp3pt0u8sve3TiTCsSIr0A6llGr1VwfdwPsmb25PjjbVwq2EcZcm6nS6DKX+I3iT1yP/Cy42TBe4FAK0WhZVtu6azYbZeZlB0U2wrpnkQoqq40Uyst67RqB9zU8k64olYeqKnGmNCzWiseOUoKwhLLoK1ExkZISVg95cr3ZN/YqdueSYW649/mdrfJAZOQM3b3b96DRuhVk3261kkFvexwe41UQtJN12u5Gz6GcPT7Pn71H70t69CPcbx/a9rcj3rDuwlk4xprKCA5VN+oJjsaB2R/75sQfezM3GIxH5myKT6PN/QErtDwgFQE6E9VDCLUZtN8F30Ko0K9IqXTRubnZ8HpFlZtzAyYUGb/ryOOIcYVWVCpBl5kCjUwlUhyF2mY80WaoXxdzEhOWe2YsNoRRWWxMt6xX/hH6P5uxF8b3rLJIlz1LpQW95pQPvqfLq0kmwohIeLs2l9PMzfQ48LvvWTbfMY1AXDg9KJDLCV2C9HUMH+CaJfOfudi/v0kIGVswLAIUEMQ9X77gqGBdfH0HIzBaV8NadPUCFBn+RiUA4D+IqVQpTTouLVY66aCGX02121",C={name:"shared",driver:"bridge"};let x=class Base extends p{options;sequelize=null;constructor(t){super(),this.options=t}async run(t,s){try{if(!this.sequelize)throw new Error("Database connection does not exist");await this.sequelize.query(t,{logging:s})}catch(s){console.error("An error occurred while trying to run the following SQL query:",t,s),e()}return null}async start(){console.log(`Starting instance of ${this.name} ⏳`),await this.stop(),await this.up(),this.emit(`${this.name}:up`);if(await this.waitUntilReady()){if(console.log(`Database is ready and accepting connections on localhost:${this.options.port} 🗄️`),await this.onDatabaseReady(),this.emit("db:ready"),this.options.logging){const t=await this.getServiceState();t&&await this.showDockerLogs(t.name)}}else console.log(`Failed to start database ${this.name} ⛔`),e(0)}async stop(){await this.down(),this.emit("db:stopped")}async onDatabaseReady(){}getDockerComposeConfig(){return{version:"3.8",services:{db:this.getService()},networks:{shared:C}}}async up(){const t=u(this.getDockerComposeConfig());return S({cwd:w(),configAsString:t,log:!0})}async down(){const t=u(this.getDockerComposeConfig());return c({cwd:w(),configAsString:t,commandOptions:["-v","--remove-orphans","--rmi","local"],log:!0})}async waitUntilReady(){try{const t="mssql"===this.name?"master":this.options.database;return this.sequelize=new A(t,this.options.username,this.options.password,{host:"localhost",port:this.options.port,dialect:this.name.replace("postgresql","postgres"),retry:{max:30,match:[v,f,T,y,D],backoffBase:1e3,backoffExponent:1},logging:!1}),this.sequelize.authenticate().then((()=>!0)).catch((t=>(console.log(t),!1)))}catch(t){return!1}}async getServiceState(){const t=u(this.getDockerComposeConfig());return(await d({configAsString:t,log:!1,commandOptions:["--all"]})).data.services.find((t=>t.name.includes(this.name)))}async showDockerLogs(t){return new Promise(((s,e)=>{const o=r("docker",["logs","-f","-n","5000",t],{cwd:w()});o.stdout.on("data",(t=>{console.log(t.toString("utf-8").trim())})),o.stderr.on("data",(t=>{console.log(t.toString("utf-8").trim())})),o.on("exit",(t=>0===t?s():e(new Error(`Docker exited with code ${t}`))))}))}};const k={port:1433,database:"dcdx",username:"sa",password:"DataCenterDX!",edition:"Developer",version:"2022"};class MSSQL extends x{name="mssql";driver="com.microsoft.sqlserver.jdbc.SQLServerDriver";options=k;version="2022";get url(){return`jdbc:sqlserver://db:${this.options.port};databaseName=${this.options.database};trustServerCertificate=true`}constructor(t=k){super({...k,...t})}async onDatabaseReady(){await this.run(`CREATE DATABASE ${this.options.database}`),await this.run(`ALTER DATABASE ${this.options.database} COLLATE SQL_Latin1_General_CP1_CS_AS`),await this.run(`ALTER DATABASE ${this.options.database} SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;`)}getService=()=>({image:`mcr.microsoft.com/mssql/server:${this.version}-latest`,ports:[`${this.options.port||1433}:1433`],environment:{ACCEPT_EULA:"y",MSSQL_SA_PASSWORD:this.options.password||"dcdx",MSSQL_PID:this.options.edition},networks:{shared:{aliases:["db","database"]}}})}const P={port:3306,database:"dcdx",username:"dcdx",password:"dcdx",version:"8.0"};class MySQL extends x{name="mysql";driver="com.mysql.jdbc.Driver";options=P;version="8.0";get url(){return`jdbc:mysql://db:${this.options.port}/${this.options.database}?sessionVariables=transaction_isolation='READ-COMMITTED'`}constructor(t=P){super({...P,...t})}async onDatabaseReady(){await this.run(`ALTER DATABASE ${this.options.database} CHARACTER SET 'utf8mb4' COLLATE utf8mb4_bin`)}getService=()=>({image:`mysql:${this.version}`,ports:[`${this.options.port||3306}:3306`],environment:{MYSQL_ROOT_PASSWORD:this.options.password||"dcdx",MYSQL_USER:this.options.username||"dcdx",MYSQL_PASSWORD:this.options.password||"dcdx",MYSQL_DATABASE:this.options.database||"dcdx"},command:["--log_bin_trust_function_creators=1"],networks:{shared:{aliases:["db","database"]}}})}const q={version:"15",database:"dcdx",port:5432,username:"dcdx",password:"dcdx"};class Postgres extends x{name="postgresql";driver="org.postgresql.Driver";options=q;version="15";get url(){return`jdbc:postgresql://db:${this.options.port}/${this.options.database}`}constructor(t=q){super({...q,...t})}getService=()=>({image:`postgres:${this.version}`,ports:[`${this.options.port||5432}:5432`],environment:{POSTGRES_USER:this.options.username||"dcdx",POSTGRES_PASSWORD:this.options.password||"dcdx",POSTGRES_DB:this.options.database||"dcdx",POSTGRES_HOST_AUTH_METHOD:"md5",POSTGRES_INITDB_ARGS:"--encoding=UTF-8 --lc-collate=C --lc-ctype=C"},networks:{shared:{aliases:["db","database"]}}})}const L=i(g(),".dcdx");class Base extends p{options;constructor(t){super(),this.options=t}get baseUrl(){const t=`http://localhost:${this.options.port}`;return this.options.contextPath?`${t}/${this.options.contextPath}`:t}getDatabaseEngine(t){switch(t){case"postgresql":return new Postgres;case"mssql":return new MSSQL;case"mysql":return new MySQL}}async start(){await this.stop(),await this.build(this.options.version),await this.database.start(this.name,this.options.version),await this.up()}async stop(){await this.database.stop(),await this.down()}async isApplicationReady(){try{const t=await n.get(`${this.baseUrl}/status`,{validateStatus:()=>!0}).catch((()=>null));if(t&&200===t.status){const{data:s}=t;if("FIRST_RUN"===s.state)return console.log(`The application ${this.name} is ready on ${this.baseUrl} 🎉`),!0}return!1}catch(t){return!1}}getDockerComposeConfig(){return{version:"3.8",services:{[this.name]:this.getService()},networks:{shared:C}}}async up(){const t=this.getDockerComposeConfig(),s=u(t);await l({cwd:w(),configAsString:s,log:!0}),this.emit(`${this.name}:up`);await this.waitUntilReady()?(this.emit(`${this.name}:ready`),await this.tailApplicationLogs()):console.log(`Failed to start ${this.name} ⛔`),e(0)}async down(){const t=u(this.getDockerComposeConfig());await c({cwd:w(),configAsString:t,commandOptions:["-v","--remove-orphans","--rmi","local"],log:!0}),this.emit(`${this.name}:stopped`)}async getServiceState(){const t=u(this.getDockerComposeConfig());return(await d({configAsString:t,log:!1,commandOptions:["--all"]})).data.services.find((t=>t.name.includes(this.name)))}async waitUntilReady(t=0){console.log(`Waiting for ${this.name} to become available... ${t}s`);const s=await this.getServiceState();return!!(s&&s.state.toLowerCase().startsWith("up")&&await this.isApplicationReady())||(t>=300?(console.error(`A timeout occurred while waiting for ${this.name} to become available ⛔`),s&&await this.showDockerLogs(s.name),!1):(await new Promise((t=>setTimeout(t,1e3))),this.waitUntilReady(t+1)))}getDockerRepositoryUrl(){return`https://bitbucket.org/atlassian-docker/docker-${"jira"===this.name?"atlassian-jira":"bamboo"===this.name?`${this.name}-server`:`atlassian-${this.name}-server`}.git`}async build(t){const s=this.getDockerRepositoryUrl(),e=i(L,this.name,"source");h(e)?await b({baseDir:e}).pull({"--recurse-submodule":null}):(m(i(L,this.name),{recursive:!0}),await b().clone(s,e,{"--recurse-submodule":null})),await new Promise(((s,o)=>{const a=r("docker",["build","-t",`dcdx/${this.name}:${t}`,"--build-arg",`${this.name.toUpperCase()}_VERSION=${t}`,"."],{cwd:e});a.stdout.on("data",(t=>{console.log(t.toString("utf-8").trim())})),a.stderr.on("data",(t=>{console.log(t.toString("utf-8").trim())})),a.on("exit",(t=>0===t?s():o(new Error(`Docker exited with code ${t}`))))}))}async tailApplicationLogs(){const t=await this.getServiceState();t&&t.state.toLowerCase().startsWith("up")&&await this.showApplicationLogs(t.name).catch((()=>null))}async showDockerLogs(t){return new Promise(((s,e)=>{const o=r("docker",["logs","-f","-n","5000",t],{cwd:w()});o.stdout.on("data",(t=>{console.log(t.toString("utf-8").trim())})),o.stderr.on("data",(t=>{console.log(t.toString("utf-8").trim())})),o.on("exit",(t=>0===t?s():e(new Error(`Docker exited with code ${t}`))))}))}async showApplicationLogs(t){return new Promise(((s,e)=>{const o=r("docker",["exec","-i",t,"tail","-F","-n","5000",this.logFilePath],{cwd:w()});o.stdout.on("data",(t=>{console.log(t.toString("utf-8").trim())})),o.stderr.on("data",(t=>{console.log(t.toString("utf-8").trim())})),o.on("SIGINT",(()=>s())),o.on("exit",(t=>0===t?s():e(new Error(`Docker exited with code ${t}`))))}))}}class Jira extends Base{name="jira";database;logFilePath="/var/atlassian/application-data/jira/log/atlassian-jira.log";constructor(t){super(t),this.database=this.getDatabaseEngine(t.database)}getService=()=>{const t=this.getVolumes(),s=this.getEnvironmentVariables();return{build:{context:getFullPath("../../assets"),dockerfile_inline:`\nFROM dcdx/${this.name}:${this.options.version}\nCOPY ./jira-data-generator-5.0.0.jar /var/atlassian/application-data/jira/plugins/installed-plugins/jira-data-generator-5.0.0.jar\nCOPY ./quickreload-5.0.2.jar /var/atlassian/application-data/jira/plugins/installed-plugins/quickreload-5.0.2.jar\nCOPY ./mysql-connector-j-8.3.0.jar /opt/atlassian/jira/lib/mysql-connector-j-8.3.0.jar\nRUN chown -R jira:jira /var/atlassian/application-data/jira`},ports:[`${this.options.port||80}:8080`,...this.options.debug?["5005:5005"]:[]],environment:Object.keys(s).length>0?s:void 0,volumes:t.length>0?t:void 0,networks:["shared"]}};getEnvironmentVariables(){const t="postgresql"===this.database.name?"postgres72":this.database.name;return{...this.options.contextPath?{ATL_TOMCAT_CONTEXTPATH:this.options.contextPath}:"",...this.options.debug?{JVM_SUPPORT_RECOMMENDED_ARGS:this.getJVMArgs()}:"",ATL_LICENSE_KEY:this.options.license||R,ATL_JDBC_URL:this.database.url,ATL_JDBC_USER:this.database.options.username,ATL_JDBC_PASSWORD:this.database.options.password,ATL_DB_DRIVER:this.database.driver,ATL_DB_TYPE:t,JIRA_SETUP_LICENSE:this.options.license||E}}getJVMArgs(){const t=[];return this.options.debug&&(t.push("-Dupm.plugin.upload.enabled=true"),t.push("-Xdebug"),t.push("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005")),this.options.quickReload&&t.push("-Dquickreload.dirs=/opt/quickreload"),t.join(" ")}getVolumes(){return[...this.options.quickReload?[`${this.options.quickReload}:/opt/quickreload`]:""]}}(async()=>{const e=t.addOption(new s("-v, --version <version>","The version of the host application").choices(["9.15.0"]).default("9.15.0")).addOption(new s("-d, --database <name>","The database engine on which the host application will run").choices(["postgresql","mysql","mssql"]).default("postgresql")).addOption(new s("-p, --port <port>","The HTTP port on which the host application will be accessible").default("80")).addOption(new s("-c, --contextPath <contextPath>","The context path on which the host application will be accessible")).addOption(new s("-qr, --quickReload <path_to_watch>","Add support for QuickReload and add the provided path to the watch list")).addOption(new s("--debug","Add support for JVM debugger on port 5005")).parse(process.argv).opts(),a=new Jira({version:e.version,database:e.database,port:Number(e.port),contextPath:e.contextPath,quickReload:e.qr,debug:e.debug});o((async()=>{console.log(`Stopping ${a.name}... ⏳`),await a.stop(),console.log(`Stopped ${a.name} 💪`)}),{wait:3e4}),await a.start()})(),process.on("SIGINT",(()=>{console.log("Received term signal, trying to stop gracefully 💪"),e()}));
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{program as a}from"commander";a.name("dcdx run").command("bamboo","Start Atlassian Bamboo (standalone)",{executableFile:"./run-bamboo.js"}).command("bitbucket","Start Atlassian Bitbucket (standalone)",{executableFile:"./run-bitbucket.js"}).command("confluence","Start Atlassian Confluence (standalone)",{executableFile:"./run-confluence.js"}).command("jira","Start Atlassian Jira (standalone)",{executableFile:"./run-jira.js"}),a.parse();
package/lib/index.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{program as a}from"commander";a.name("dcdx").description("The Unofficial Atlassian Data Center Plugin Development CLI").version("0.0.1"),a.command("run","Start the Atlassian host application (standalone)",{executableFile:"./commands/run.js"}),a.command("run:jira").description("Start Atlassian Jira").action((()=>{process.argv.splice(2,1,"run","jira"),a.parse(process.argv)})),a.command("run:confluence").description("Start Atlassian Confluence").action((()=>{process.argv.splice(2,1,"run","confluence"),a.parse(process.argv)})),a.command("run:bitbucket").description("Start Atlassian Bitbucket").action((()=>{process.argv.splice(2,1,"run","bitbucket"),a.parse(process.argv)})),a.command("run:bamboo").description("Start Atlassian Bamboo").action((()=>{process.argv.splice(2,1,"run","bamboo"),a.parse(process.argv)})),a.command("database","Start a database engine (standalone)",{executableFile:"./commands/database.js"}),a.command("database:postgres").description("Start PostgreSQL").action((()=>{process.argv.splice(2,1,"database","postgresql"),a.parse(process.argv)})),a.command("database:postgresql").description("Start PostgreSQL").action((()=>{process.argv.splice(2,1,"database","postgresql"),a.parse(process.argv)})),a.command("database:mysql").description("Start MySQL").action((()=>{process.argv.splice(2,1,"database","mysql"),a.parse(process.argv)})),a.command("database:mssql").description("Start Microsoft Sql Server").action((()=>{process.argv.splice(2,1,"database","mssql"),a.parse(process.argv)})),a.command("profile","Run a predefined profile",{executableFile:"./commands/profile.js"}).on("command:*",(s=>{const e=s[0];process.argv.splice(2,1,"profile",e),a.parse(process.argv)})),a.parse(process.argv);
@@ -0,0 +1,16 @@
1
+ import { ApplicationOptions } from '../types/ApplicationOptions';
2
+ import { DatabaseEngine } from '../types/DatabaseEngine';
3
+ import { Service } from '../types/DockerComposeV3';
4
+ import { SupportedApplications } from '../types/SupportedApplications';
5
+ import { Base } from './base';
6
+ export declare class Bamboo extends Base {
7
+ name: SupportedApplications;
8
+ database: DatabaseEngine;
9
+ logFilePath: string;
10
+ constructor(options: ApplicationOptions);
11
+ protected getService: () => Service;
12
+ protected isApplicationReady(): Promise<boolean>;
13
+ private getEnvironmentVariables;
14
+ private getJVMArgs;
15
+ private getVolumes;
16
+ }
@@ -0,0 +1,30 @@
1
+ /// <reference types="node" />
2
+ import EventEmitter from 'events';
3
+ import { ApplicationOptions } from '../types/ApplicationOptions';
4
+ import { DatabaseEngine } from '../types/DatabaseEngine';
5
+ import { Service } from '../types/DockerComposeV3';
6
+ import { SupportedApplications } from '../types/SupportedApplications';
7
+ import { SupportedDatabaseEngines } from '../types/SupportedDatabaseEngines';
8
+ export declare abstract class Base extends EventEmitter {
9
+ protected options: ApplicationOptions;
10
+ abstract get name(): SupportedApplications;
11
+ abstract get database(): DatabaseEngine;
12
+ abstract get logFilePath(): string;
13
+ constructor(options: ApplicationOptions);
14
+ protected get baseUrl(): string;
15
+ getDatabaseEngine(name: SupportedDatabaseEngines): DatabaseEngine;
16
+ start(): Promise<void>;
17
+ stop(): Promise<void>;
18
+ protected abstract getService(): Service;
19
+ protected isApplicationReady(): Promise<boolean>;
20
+ private getDockerComposeConfig;
21
+ private up;
22
+ private down;
23
+ private getServiceState;
24
+ private waitUntilReady;
25
+ private getDockerRepositoryUrl;
26
+ private build;
27
+ private tailApplicationLogs;
28
+ private showDockerLogs;
29
+ private showApplicationLogs;
30
+ }
@@ -0,0 +1,15 @@
1
+ import { ApplicationOptions } from '../types/ApplicationOptions';
2
+ import { DatabaseEngine } from '../types/DatabaseEngine';
3
+ import { Service } from '../types/DockerComposeV3';
4
+ import { SupportedApplications } from '../types/SupportedApplications';
5
+ import { Base } from './base';
6
+ export declare class Bitbucket extends Base {
7
+ name: SupportedApplications;
8
+ database: DatabaseEngine;
9
+ logFilePath: string;
10
+ constructor(options: ApplicationOptions);
11
+ protected getService: () => Service;
12
+ private getEnvironmentVariables;
13
+ private getJVMArgs;
14
+ private getVolumes;
15
+ }
@@ -0,0 +1,15 @@
1
+ import { ApplicationOptions } from '../types/ApplicationOptions';
2
+ import { DatabaseEngine } from '../types/DatabaseEngine';
3
+ import { Service } from '../types/DockerComposeV3';
4
+ import { SupportedApplications } from '../types/SupportedApplications';
5
+ import { Base } from './base';
6
+ export declare class Confluence extends Base {
7
+ name: SupportedApplications;
8
+ database: DatabaseEngine;
9
+ logFilePath: string;
10
+ constructor(options: ApplicationOptions);
11
+ protected getService: () => Service;
12
+ private getEnvironmentVariables;
13
+ private getJVMArgs;
14
+ private getVolumes;
15
+ }
@@ -0,0 +1,15 @@
1
+ import { ApplicationOptions } from '../types/ApplicationOptions';
2
+ import { DatabaseEngine } from '../types/DatabaseEngine';
3
+ import { Service } from '../types/DockerComposeV3';
4
+ import { SupportedApplications } from '../types/SupportedApplications';
5
+ import { Base } from './base';
6
+ export declare class Jira extends Base {
7
+ name: SupportedApplications;
8
+ database: DatabaseEngine;
9
+ logFilePath: string;
10
+ constructor(options: ApplicationOptions);
11
+ protected getService: () => Service;
12
+ private getEnvironmentVariables;
13
+ private getJVMArgs;
14
+ private getVolumes;
15
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,30 @@
1
+ /// <reference types="node" />
2
+ import EventEmitter from 'events';
3
+ import { DatabaseEngine } from '../types/DatabaseEngine';
4
+ import { DatabaseOptions } from '../types/DatabaseOptions';
5
+ import { Service } from '../types/DockerComposeV3';
6
+ import { SupportedDatabaseDrivers } from '../types/SupportedDatabaseDrivers';
7
+ import { SupportedDatabaseEngines } from '../types/SupportedDatabaseEngines';
8
+ export declare abstract class Base extends EventEmitter implements DatabaseEngine {
9
+ options: DatabaseOptions;
10
+ private sequelize;
11
+ abstract get name(): SupportedDatabaseEngines;
12
+ abstract get driver(): SupportedDatabaseDrivers;
13
+ abstract get version(): string;
14
+ abstract get url(): string;
15
+ constructor(options: DatabaseOptions);
16
+ run(sql: string | {
17
+ query: string;
18
+ values: unknown[];
19
+ }, logging?: boolean): Promise<[unknown[], unknown] | null>;
20
+ start(): Promise<void>;
21
+ stop(): Promise<void>;
22
+ protected abstract getService(): Service;
23
+ protected onDatabaseReady(): Promise<void>;
24
+ private getDockerComposeConfig;
25
+ private up;
26
+ private down;
27
+ private waitUntilReady;
28
+ private getServiceState;
29
+ private showDockerLogs;
30
+ }
@@ -0,0 +1,19 @@
1
+ import { DatabaseOptions } from '../types/DatabaseOptions';
2
+ import { Service } from '../types/DockerComposeV3';
3
+ import { SupportedDatabaseDrivers } from '../types/SupportedDatabaseDrivers';
4
+ import { SupportedDatabaseEngines } from '../types/SupportedDatabaseEngines';
5
+ import { Base } from './base';
6
+ export type MSSQLOptions = DatabaseOptions & {
7
+ edition: 'Developer' | 'Express' | 'Standard' | 'Enterprise' | 'EnterpriseCore';
8
+ version: '2017' | '2019' | '2022';
9
+ };
10
+ export declare class MSSQL extends Base {
11
+ name: SupportedDatabaseEngines;
12
+ driver: SupportedDatabaseDrivers;
13
+ options: MSSQLOptions;
14
+ version: '2017' | '2019' | '2022';
15
+ get url(): string;
16
+ constructor(options?: MSSQLOptions);
17
+ protected onDatabaseReady(): Promise<void>;
18
+ protected getService: () => Service;
19
+ }
@@ -0,0 +1,19 @@
1
+ import { DatabaseOptions } from '../types/DatabaseOptions';
2
+ import { Service } from '../types/DockerComposeV3';
3
+ import { SupportedDatabaseDrivers } from '../types/SupportedDatabaseDrivers';
4
+ import { SupportedDatabaseEngines } from '../types/SupportedDatabaseEngines';
5
+ import { Base } from './base';
6
+ type MySQLOptions = DatabaseOptions & {
7
+ version: '8.0' | '8.3';
8
+ };
9
+ export declare class MySQL extends Base {
10
+ name: SupportedDatabaseEngines;
11
+ driver: SupportedDatabaseDrivers;
12
+ options: MySQLOptions;
13
+ version: '8.0' | '8.3';
14
+ get url(): string;
15
+ constructor(options?: MySQLOptions);
16
+ protected onDatabaseReady(): Promise<void>;
17
+ protected getService: () => Service;
18
+ }
19
+ export {};
@@ -0,0 +1,18 @@
1
+ import { DatabaseOptions } from '../types/DatabaseOptions';
2
+ import { Service } from '../types/DockerComposeV3';
3
+ import { SupportedDatabaseDrivers } from '../types/SupportedDatabaseDrivers';
4
+ import { SupportedDatabaseEngines } from '../types/SupportedDatabaseEngines';
5
+ import { Base } from './base';
6
+ type PostgresOptions = DatabaseOptions & {
7
+ version?: '12' | '13' | '14' | '15';
8
+ };
9
+ export declare class Postgres extends Base {
10
+ name: SupportedDatabaseEngines;
11
+ driver: SupportedDatabaseDrivers;
12
+ options: PostgresOptions;
13
+ version: string;
14
+ get url(): string;
15
+ constructor(options?: PostgresOptions);
16
+ protected getService: () => Service;
17
+ }
18
+ export {};
@@ -0,0 +1 @@
1
+ export declare const getFullPath: (relativePath: string) => string;
@@ -0,0 +1,2 @@
1
+ import { SupportedApplications } from '../types/SupportedApplications';
2
+ export declare const timebomb: Record<SupportedApplications, string>;
@@ -0,0 +1,2 @@
1
+ import type { Network } from '../types/DockerComposeV3';
2
+ export declare const network: Network;
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,10 @@
1
+ import { SupportedDatabaseEngines } from './SupportedDatabaseEngines';
2
+ export type ApplicationOptions = {
3
+ version: string;
4
+ database: SupportedDatabaseEngines;
5
+ port: number;
6
+ contextPath?: string;
7
+ quickReload?: boolean;
8
+ license?: string;
9
+ debug?: boolean;
10
+ };
@@ -0,0 +1,19 @@
1
+ /// <reference types="node" />
2
+ import EventEmitter from 'events';
3
+ import { DatabaseOptions } from './DatabaseOptions';
4
+ import { SupportedApplications } from './SupportedApplications';
5
+ import { SupportedDatabaseDrivers } from './SupportedDatabaseDrivers';
6
+ import { SupportedDatabaseEngines } from './SupportedDatabaseEngines';
7
+ export interface DatabaseEngine extends EventEmitter {
8
+ name: SupportedDatabaseEngines;
9
+ url: string;
10
+ driver: SupportedDatabaseDrivers;
11
+ options: DatabaseOptions;
12
+ start(): Promise<void>;
13
+ start(application: SupportedApplications, version: string): Promise<void>;
14
+ stop(): Promise<void>;
15
+ run(sql: string | {
16
+ query: string;
17
+ values: unknown[];
18
+ }): Promise<[unknown[], unknown] | null>;
19
+ }
@@ -0,0 +1,7 @@
1
+ export type DatabaseOptions = {
2
+ port: number;
3
+ database: string;
4
+ username: string;
5
+ password: string;
6
+ logging?: boolean;
7
+ };
@@ -0,0 +1 @@
1
+ export type SupportedApplications = 'jira' | 'confluence' | 'bitbucket' | 'bamboo';
@@ -0,0 +1 @@
1
+ export type SupportedDatabaseDrivers = 'com.microsoft.sqlserver.jdbc.SQLServerDriver' | 'com.mysql.jdbc.Driver' | 'oracle.jdbc.OracleDriver' | 'org.postgresql.Driver';
@@ -0,0 +1 @@
1
+ export type SupportedDatabaseEngines = 'postgresql' | 'mysql' | 'mssql';
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "dcdx",
3
+ "version": "1.0.0",
4
+ "author": "Collabsoft <info@collabsoft.net>",
5
+ "description": "The Unofficial CLI for Atlassian Data Center Plugin Development",
6
+ "type": "module",
7
+ "main": "./lib/index.js",
8
+ "types": "./lib/types/index.d.ts",
9
+ "files": [
10
+ "assets/",
11
+ "lib/",
12
+ "LICENSE",
13
+ "README",
14
+ "package.json"
15
+ ],
16
+ "bin": "./lib/index.js",
17
+ "engines": {
18
+ "node": ">=18"
19
+ },
20
+ "scripts": {
21
+ "clean": "rm -rf dist && rm -rf lib",
22
+ "lint": "yarn run eslint .",
23
+ "build": "yarn clean && yarn lint && yarn build:esm && yarn build:types",
24
+ "build:esm": "yarn run tsc && yarn run rollup -c rollup.config.js",
25
+ "build:types": "yarn run tsc --emitDeclarationOnly --outDir lib/types/",
26
+ "watch": "yarn run nodemon --watch src -e '.ts' --exec 'yarn build'",
27
+ "start": "./lib/index.js",
28
+ "reinstall": "yarn clean && yarn install",
29
+ "prepack": "yarn build"
30
+ },
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/collabsoft-net/dcdx.git"
34
+ },
35
+ "license": "MIT",
36
+ "bugs": {
37
+ "url": "https://github.com/collabsoft-net/dcdx/issues"
38
+ },
39
+ "homepage": "https://github.com/collabsoft-net/dcdx#readme",
40
+ "packageManager": "yarn@4.1.1",
41
+ "devDependencies": {
42
+ "@eslint/js": "9.0.0",
43
+ "@rollup/plugin-commonjs": "25.0.7",
44
+ "@rollup/plugin-json": "6.1.0",
45
+ "@rollup/plugin-node-resolve": "15.2.3",
46
+ "@rollup/plugin-terser": "0.4.4",
47
+ "@types/js-yaml": "4",
48
+ "@types/node": "18.16.0",
49
+ "@types/pg": "8",
50
+ "@typescript-eslint/eslint-plugin": "7.6.0",
51
+ "@typescript-eslint/parser": "7.6.0",
52
+ "eslint": "9.0.0",
53
+ "eslint-plugin-simple-import-sort": "12.0.0",
54
+ "nodemon": "3.1.0",
55
+ "rollup": "4.14.1",
56
+ "rollup-plugin-executable": "1.6.3",
57
+ "typescript": "5.4.4",
58
+ "typescript-eslint": "7.6.0"
59
+ },
60
+ "dependencies": {
61
+ "axios": "1.6.8",
62
+ "commander": "12.0.0",
63
+ "docker-compose": "0.24.8",
64
+ "exit-hook": "4.0.0",
65
+ "js-yaml": "4.1.0",
66
+ "mysql2": "3.9.4",
67
+ "pg": "8.11.5",
68
+ "sequelize": "6.37.2",
69
+ "simple-git": "3.24.0",
70
+ "tedious": "18.1.0"
71
+ }
72
+ }