quidproquo-cli 0.1.8 → 0.1.10
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.
- package/lib/commonjs/cli/commandRegistry.js +5 -0
- package/lib/commonjs/cli/commandRegistry.js.map +1 -1
- package/lib/commonjs/commands/checkCircular.d.ts +1 -0
- package/lib/commonjs/commands/checkCircular.js +70 -0
- package/lib/commonjs/commands/checkCircular.js.map +1 -0
- package/lib/commonjs/commands/synth.js +12 -1
- package/lib/commonjs/commands/synth.js.map +1 -1
- package/lib/commonjs/lib/circularImports.d.ts +3 -0
- package/lib/commonjs/lib/circularImports.js +79 -0
- package/lib/commonjs/lib/circularImports.js.map +1 -0
- package/lib/commonjs/lib/runCommand.d.ts +1 -0
- package/lib/commonjs/lib/runCommand.js +28 -3
- package/lib/commonjs/lib/runCommand.js.map +1 -1
- package/lib/commonjs/platforms/aws/goDocker.js +17 -32
- package/lib/commonjs/platforms/aws/goDocker.js.map +1 -1
- package/lib/esm/cli/commandRegistry.js +5 -0
- package/lib/esm/cli/commandRegistry.js.map +1 -1
- package/lib/esm/commands/checkCircular.d.ts +1 -0
- package/lib/esm/commands/checkCircular.js +55 -0
- package/lib/esm/commands/checkCircular.js.map +1 -0
- package/lib/esm/commands/synth.js +12 -1
- package/lib/esm/commands/synth.js.map +1 -1
- package/lib/esm/lib/circularImports.d.ts +3 -0
- package/lib/esm/lib/circularImports.js +61 -0
- package/lib/esm/lib/circularImports.js.map +1 -0
- package/lib/esm/lib/runCommand.d.ts +1 -0
- package/lib/esm/lib/runCommand.js +25 -2
- package/lib/esm/lib/runCommand.js.map +1 -1
- package/lib/esm/platforms/aws/goDocker.js +17 -32
- package/lib/esm/platforms/aws/goDocker.js.map +1 -1
- package/package.json +11 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"goDocker.js","sourceRoot":"","sources":["../../../../src/platforms/aws/goDocker.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,yEAAyE;AACzE,+CAA+C;AAC/C,EAAE;AACF,6EAA6E;AAC7E,qEAAqE;AACrE,qDAAqD;AACrD,mEAAmE;AACnE,6EAA6E;AAC7E,6EAA6E;AAC7E,oEAAoE;AACpE,mEAAmE;AACnE,4EAA4E;AAC5E,6EAA6E;AAC7E,oBAAoB;AACpB,sEAAsE;AACtE,gDAAgD;AAChD,+EAA+E;AAC/E,6EAA6E;AAC7E,qEAAqE;AACrE,EAAE;AACF,yEAAyE;AACzE,4CAA4C;AAC5C,EAAE;AACF,qEAAqE;AACrE,2EAA2E;AAC3E,yEAAyE;AACzE,mBAAmB;AACnB,uEAAgE;AAChE,uEAAkE;AAElE,4CAAoB;AACpB,gDAAwB;AAExB,gDAAoD;AAEpD,mDAA6F;AAC7F,2CAA6C;AAC7C,qDAA2F;AAC3F,mDAAgD;AAChD,qDAAuF;AACvF,iDAAgE;AAChE,6CAA4D;AAC5D,2CAA+D;AAC/D,qDAAyD;AACzD,qCAA0D;AAC1D,qCAA6D;AAC7D,qCAAuF;AACvF,2CAAqD;AAErD,MAAM,SAAS,GAAG,kBAAkB,CAAC;AACrC,MAAM,aAAa,GAAG,gBAAgB,CAAC;AAEvC,MAAM,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,IAAI,CAAC,CAAC;AAC/E,MAAM,kBAAkB,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,IAAI,QAAQ,CAAC;AAExF,0EAA0E;AAC1E,wEAAwE;AACxE,MAAM,mBAAmB,GAAG;IAC1B,mBAAmB;IACnB,uBAAuB;IACvB,mBAAmB;IACnB,YAAY;IACZ,oBAAoB;IACpB,qBAAqB;CACtB,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,OAAe,EAAE,WAAmB,EAAU,EAAE,CAAC,cAAI,CAAC,IAAI,CAAC,IAAA,mBAAO,GAAE,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;AAE9I,MAAM,mBAAmB,GAAG,GAAwB,EAAE;IACpD,IAAI,CAAC;QACH,MAAM,IAAA,uBAAU,EAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,gDAAgD,CAAC,CAAC,CAAC;IACrG,CAAC;IAAC,WAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IACpF,CAAC;AACH,CAAC,CAAA,CAAC;AAEF,MAAM,kBAAkB,GAAG,GAAwB,EAAE;IACnD,4EAA4E;IAC5E,iDAAiD;IACjD,iEAAiE;IACjE,MAAM,UAAU,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC,OAAiB,CAAC;IACrE,OAAO,CAAC,GAAG,CAAC,4BAA4B,SAAS,cAAc,UAAU,GAAG,CAAC,CAAC;IAC9E,MAAM,IAAA,uBAAU,EAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,UAAU,EAAE,EAAE,IAAA,qBAAY,GAAE,CAAC,CAAC,CAAC;AACrH,CAAC,CAAA,CAAC;AAEF,4EAA4E;AAC5E,4EAA4E;AAC5E,8EAA8E;AAC9E,0EAA0E;AAC1E,+DAA+D;AAC/D,MAAM,iBAAiB,GAAG,CACxB,KAAa,EACb,OAAe,EACf,WAAmB,EACnB,SAAgC,EAChC,SAAiB,EACF,EAAE;IACjB,MAAM,aAAa,GAAG,GAAG,WAAW,IAAI,SAAS,EAAE,CAAC;IACpD,OAAO,IAAA,+BAAkB,EACvB,GAAG,SAAS,IAAI,WAAW,EAAE,EAC7B,QAAQ,EACR;QACE,wEAAwE;QACxE,iCAAiC;QACjC,IAAI;QACJ,IAAI;QACJ,aAAa;QACb,YAAY;QACZ,MAAM;QACN,GAAG;QACH,QAAQ;QACR,KAAK;QACL,MAAM;QACN,QAAQ;QACR,aAAa;QACb,IAAI;QACJ,IAAI,WAAW,CAAC,OAAO,EAAE,WAAW,CAAC,gBAAgB;QACrD,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACtD,SAAS;QACT,MAAM;QACN,IAAI;QACJ,iDAAiD,SAAS,mEAAmE;KAC9H,EACD,EAAE,KAAK,EAAE,CACV,CAAC;AACJ,CAAC,CAAC;AAEF,4EAA4E;AAC5E,4EAA4E;AAC5E,6EAA6E;AAC7E,2CAA2C;AAC3C,MAAM,eAAe,GAAG,CAAO,KAAa,EAAE,OAAe,EAAE,WAAmB,EAAiB,EAAE;IACnG,MAAM,aAAa,GAAG,GAAG,WAAW,QAAQ,CAAC;IAC7C,KAAK,MAAM,WAAW,IAAI,IAAA,kCAAsB,EAAC,OAAO,EAAE,WAAW,CAAC,EAAE,CAAC;QACvE,MAAM,IAAA,+BAAkB,EACtB,SAAS,WAAW,EAAE,EACtB,QAAQ,EACR;YACE,IAAI;YACJ,IAAI;YACJ,aAAa;YACb,YAAY;YACZ,MAAM;YACN,GAAG;YACH,QAAQ;YACR,KAAK;YACL,MAAM;YACN,QAAQ;YACR,aAAa;YACb,IAAI;YACJ,IAAI,IAAA,uBAAe,EAAC,OAAO,EAAE,WAAW,CAAC,aAAa;YACtD,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACtD,aAAa;YACb,IAAI;YACJ,MAAM;YACN,QAAQ;YACR,WAAW;SACZ,EACD,EAAE,KAAK,EAAE,CACV,CAAC;IACJ,CAAC;AACH,CAAC,CAAA,CAAC;AAEF,4EAA4E;AAC5E,6EAA6E;AAC7E,4EAA4E;AAC5E,8EAA8E;AAC9E,iFAAiF;AACjF,0EAA0E;AAC1E,MAAM,mBAAmB,GAAG,CAAO,KAAa,EAAE,OAAe,EAAE,WAAmB,EAAiB,EAAE;IACvG,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,IAAA,6BAAoB,EAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC5G,MAAM,aAAa,GAAG,GAAG,WAAW,UAAU,CAAC;IAE/C,8EAA8E;IAC9E,6CAA6C;IAC7C,MAAM,YAAY,GAAe;QAC/B,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,YAAY,EAAE,EAAE,QAAQ,UAAU,IAAI,aAAa,IAAI,YAAY,EAAE,CAAC;QACjG,CAAC,IAAI,EAAE,IAAI,EAAE,wBAAwB,EAAE,QAAQ,UAAU,IAAI,aAAa,gBAAgB,CAAC;KAC5F,CAAC;IAEF,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACvC,MAAM,IAAA,+BAAkB,EACtB,WAAW,WAAW,EAAE,EACxB,QAAQ,EACR;YACE,IAAI;YACJ,IAAI;YACJ,aAAa;YACb,YAAY;YACZ,MAAM;YACN,GAAG;YACH,QAAQ;YACR,KAAK;YACL,MAAM;YACN,QAAQ;YACR,aAAa;YACb,IAAI;YACJ,IAAI,WAAW,eAAe;YAC9B,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACtD,aAAa;YACb,GAAG,WAAW;SACf,EACD,EAAE,KAAK,EAAE,CACV,CAAC;IACJ,CAAC;AACH,CAAC,CAAA,CAAC;AAEK,MAAM,WAAW,GAAG,CAAO,OAAe,EAAE,IAAgB,EAAiB,EAAE;IACpF,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAC9B,OAAO;IACT,CAAC;IAED,IAAI,CAAC,MAAM,IAAA,sCAAqB,GAAE,CAAC,KAAK,KAAK,EAAE,CAAC;QAC9C,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;QACnD,OAAO;IACT,CAAC;IAED,IAAA,qBAAY,EAAC,WAAW,CAAC,CAAC;IAE1B,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAA,2BAAkB,EAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvC,IAAA,mBAAU,EAAC,WAAW,CAAC,CAAC;QACxB,OAAO;IACT,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAC9B,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,MAAM,IAAA,0BAAiB,EAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxC,CAAC;QACD,MAAM,IAAA,6BAAoB,EAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzC,IAAA,mBAAU,EAAC,WAAW,CAAC,CAAC;QACxB,OAAO;IACT,CAAC;IAED,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAElC,MAAM,SAAS,GAAG,MAAM,KAAK,KAAK,CAAC;IACnC,MAAM,OAAO,GAAG,SAAS,IAAI,MAAM,KAAK,KAAK,CAAC;IAC9C,MAAM,OAAO,GAAG,SAAS,IAAI,MAAM,KAAK,KAAK,CAAC;IAC9C,MAAM,OAAO,GAAG,SAAS,IAAI,MAAM,KAAK,KAAK,CAAC;IAC9C,MAAM,SAAS,GAAG,SAAS,IAAI,MAAM,KAAK,OAAO,CAAC;IAClD,MAAM,cAAc,GAAG,OAAO,IAAI,OAAO,IAAI,OAAO,CAAC;IAErD,MAAM,YAAY,GAAG,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,oCAAwB,EAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE5G,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;IACtC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAEjC,2EAA2E;IAC3E,uEAAuE;IACvE,IAAI,cAAc,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9C,MAAM,mBAAmB,EAAE,CAAC;IAC9B,CAAC;IACD,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,kBAAkB,EAAE,CAAC;IAC7B,CAAC;IAED,8CAA8C;IAC9C,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IAEjD,MAAM,IAAA,kBAAU,EAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAEvC,4EAA4E;IAC5E,6EAA6E;IAC7E,yEAAyE;IACzE,gCAAgC;IAChC,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;IAC3C,MAAM,IAAA,uBAAU,EAAC,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,CAAC,CAAC,CAAC;IAE1E,qEAAqE;IACrE,iFAAiF;IACjF,MAAM,gBAAgB,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACtF,KAAK,MAAM,OAAO,IAAI,gBAAgB,EAAE,CAAC;QACvC,MAAM,IAAA,oBAAY,EAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,+EAA+E;IAC/E,sFAAsF;IACtF,oFAAoF;IACpF,MAAM,iBAAiB,GAAG,OAAO,CAAC,CAAC,CAAC,IAAA,0CAA6B,EAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE1F,0EAA0E;IAC1E,gFAAgF;IAChF,0EAA0E;IAC1E,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAA,uBAAU,EAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,IAAA,2BAAgB,EACd,cAAc,EACd,MAAM,IAAA,mBAAQ,EACZ,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACzB,KAAK,EAAE,cAAc,OAAO,EAAE;YAC9B,GAAG,EAAE,GAAS,EAAE;gBACd,OAAO,CAAC,GAAG,CAAC,kBAAkB,OAAO,GAAG,CAAC,CAAC;gBAC1C,MAAM,SAAS,GAAG,IAAA,iCAAoB,EAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBACzD,MAAM,IAAA,qBAAS,EAAC,IAAA,iDAAsB,EAAC,SAAS,EAAE,cAAI,CAAC,IAAI,CAAC,IAAA,+BAAmB,EAAC,OAAO,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;YAClH,CAAC,CAAA;SACF,CAAC,CAAC,EACH,iBAAiB,CAClB,CACF,CAAC;IACJ,CAAC;IAED,IAAA,2BAAgB,EACd,gBAAgB,EAChB,MAAM,IAAA,mBAAQ,EACZ,YAAY,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC7B,KAAK,EAAE,gBAAgB,OAAO,EAAE;QAChC,GAAG,EAAE,GAAS,EAAE;YACd,OAAO,CAAC,GAAG,CAAC,oBAAoB,OAAO,GAAG,CAAC,CAAC;YAC5C,MAAM,IAAA,mBAAW,EAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACtC,CAAC,CAAA;KACF,CAAC,CAAC,EACH,iBAAiB,CAClB,CACF,CAAC;IAEF,+EAA+E;IAC/E,+EAA+E;IAC/E,qCAAqC;IACrC,IAAA,2BAAgB,EACd,iBAAiB,EACjB,MAAM,IAAA,mBAAQ,EACZ,iBAAiB,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAClC,KAAK,EAAE,iBAAiB,OAAO,EAAE;QACjC,GAAG,EAAE,GAAS,EAAE;YACd,OAAO,CAAC,GAAG,CAAC,+BAA+B,OAAO,GAAG,CAAC,CAAC;YACvD,MAAM,IAAA,oBAAW,EAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACtC,CAAC,CAAA;KACF,CAAC,CAAC,EACH,iBAAiB,CAClB,CACF,CAAC;IAEF,IAAI,cAAc,EAAE,CAAC;QACnB,yEAAyE;QACzE,qEAAqE;QACrE,wCAAwC;QACxC,IAAA,2BAAgB,EACd,WAAW,EACX,MAAM,IAAA,mBAAQ,EACZ,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACzB,KAAK,EAAE,aAAa,OAAO,EAAE;YAC7B,GAAG,EAAE,GAAS,EAAE;gBACd,MAAM,SAAS,GAAG,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBAChD,YAAE,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBACvD,MAAM,IAAA,+BAAkB,EACtB,aAAa,OAAO,EAAE,EACtB,KAAK,EACL,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,IAAA,yBAAgB,GAAE,GAAG,EAAE,UAAU,EAAE,IAAI,SAAS,GAAG,CAAC,EAC7F;oBACE,GAAG,EAAE,IAAA,mBAAO,GAAE;oBACd,GAAG,EAAE,EAAE,mBAAmB,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE;oBAC/D,KAAK,EAAE,IAAA,4BAAe,GAAE;iBACzB,CACF,CAAC;YACJ,CAAC,CAAA;SACF,CAAC,CAAC,EACH,iBAAiB,CAClB,CACF,CAAC;IACJ,CAAC;IAED,4EAA4E;IAC5E,MAAM,UAAU,GAAG,IAAI,GAAG,CACxB,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QACvB,MAAM,SAAS,GAAG,IAAA,iCAAoB,EAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACzD,OAAO;YACL,OAAO;YACP;gBACE,GAAG,EAAE,+CAAoB,CAAC,eAAe,CAAC,SAAS,CAAC;gBACpD,GAAG,EAAE,+CAAoB,CAAC,eAAe,CAAC,SAAS,CAAC;gBACpD,GAAG,EAAE,+CAAoB,CAAC,eAAe,CAAC,SAAS,CAAC;aACrD;SACF,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;IAEF,2EAA2E;IAC3E,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;QAC/D,IAAA,qBAAY,EAAC,SAAS,CAAC,CAAC;QACxB,IAAA,2BAAgB,EACd,YAAY,EACZ,MAAM,IAAA,mBAAQ,EACZ,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACzB,KAAK,EAAE,OAAO,OAAO,EAAE;YACvB,GAAG,EAAE,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAA,4BAAe,GAAE,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC,GAAG,CAAC;SACvG,CAAC,CAAC,EACH,kBAAkB,CACnB,CACF,CAAC;QACF,IAAA,mBAAU,EAAC,SAAS,CAAC,CAAC;IACxB,CAAC;IAED,sDAAsD;IACtD,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAC;QACrE,IAAA,qBAAY,EAAC,YAAY,CAAC,CAAC;QAC3B,IAAA,2BAAgB,EACd,gBAAgB,EAChB,MAAM,IAAA,mBAAQ,EACX,CAAC,KAAK,EAAE,KAAK,CAAW;aACtB,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;aAChE,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE,CACrB,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACzB,KAAK,EAAE,GAAG,SAAS,IAAI,OAAO,EAAE;YAChC,GAAG,EAAE,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAA,4BAAe,GAAE,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC,SAAS,CAAC,CAAC;SAClH,CAAC,CAAC,CACJ,EACH,kBAAkB,CACnB,CACF,CAAC;QACF,IAAA,mBAAU,EAAC,YAAY,CAAC,CAAC;IAC3B,CAAC;IAED,oEAAoE;IACpE,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;QAC9D,IAAA,qBAAY,EAAC,WAAW,CAAC,CAAC;QAC1B,IAAA,2BAAgB,EACd,YAAY,EACZ,MAAM,IAAA,mBAAQ,EACZ,YAAY,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAC7B,KAAK,EAAE,SAAS,OAAO,EAAE;YACzB,GAAG,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,IAAA,4BAAe,GAAE,EAAE,OAAO,EAAE,OAAO,CAAC;SAChE,CAAC,CAAC,EACH,kBAAkB,CACnB,CACF,CAAC;QACF,IAAA,mBAAU,EAAC,WAAW,CAAC,CAAC;IAC1B,CAAC;IAED,mFAAmF;IACnF,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,+DAA+D,CAAC,CAAC;QAC7E,IAAA,qBAAY,EAAC,aAAa,CAAC,CAAC;QAC5B,IAAA,2BAAgB,EACd,mBAAmB,EACnB,MAAM,IAAA,mBAAQ,EACZ,iBAAiB,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAClC,KAAK,EAAE,WAAW,OAAO,EAAE;YAC3B,GAAG,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC,IAAA,4BAAe,GAAE,EAAE,OAAO,EAAE,OAAO,CAAC;SACpE,CAAC,CAAC,EACH,kBAAkB,CACnB,CACF,CAAC;QACF,IAAA,mBAAU,EAAC,aAAa,CAAC,CAAC;IAC5B,CAAC;IAED,IAAA,mBAAU,EAAC,WAAW,CAAC,CAAC;AAC1B,CAAC,CAAA,CAAC;AAvPW,QAAA,WAAW,eAuPtB","sourcesContent":["// `qpq go:docker` — asks the same questions as `qpq go`, then deploys in\n// parallel via docker instead of sequentially:\n//\n// 1. Build everything locally first: QPQ config synth, rspack API bundles,\n// rspack view bundles, rspack federated-remote bundles, and one\n// self-contained CDK cloud assembly per service\n// (`cdk synth --output dist/qpq/cdk-docker/<app>/<service>`).\n// 2. Wave 1 (inf): one docker container per service deploys its inf stack,\n// all concurrently. Containers run only the CDK CLI against the mounted\n// pre-synthesized assembly — the workspace (and its npm-linked\n// quidproquo packages) never needs to exist inside the image.\n// 3. Wave 2 (api + web): once every inf stack is done, api and web stacks\n// for all services deploy concurrently (they depend only on inf, not on\n// each other).\n// 4. Views: the already-built bundles are synced to S3, one aws-cli\n// container per service, all concurrently.\n// 5. Publish: the already-built federated remotes (backends that opt in with\n// defineFederatedModuleStore(...)) are synced to S3 and their manifests\n// flipped, one aws-cli container per service, all concurrently.\n//\n// domain/bootstrap menu options deploy host-side exactly like `qpq go` —\n// a single stack gains nothing from docker.\n//\n// Requires the same env as `go` plus a running docker daemon. Knobs:\n// GO_DOCKER_BUILD_CONCURRENCY (default 4 — local builds are CPU-bound) and\n// GO_DOCKER_DEPLOY_CONCURRENCY (default unlimited — deploys just wait on\n// CloudFormation).\nimport { qpqDeployAwsCdkUtils } from 'quidproquo-deploy-awscdk';\nimport { getServiceRspackConfig } from 'quidproquo-deploy-rspack';\n\nimport fs from 'fs';\nimport path from 'path';\n\nimport { synthCommand } from '../../commands/synth';\nimport { DeployPlan } from '../../lib/deployPrompts';\nimport { getRoot, getServiceDirectory, getServiceNamesWithViews } from '../../lib/discovery';\nimport { runAppHook } from '../../lib/hooks';\nimport { getServiceNamesWithFederation, loadServiceQpqConfig } from '../../lib/qpqConfigs';\nimport { runRspack } from '../../lib/rspackRun';\nimport { nextPrefixColor, runCommand, runCommandPrefixed } from '../../lib/runCommand';\nimport { assertNoFailures, runTasks } from '../../lib/runTasks';\nimport { logTimeEnd, logTimeStart } from '../../lib/timing';\nimport { bundleViews, getViewsDistDir } from '../../lib/views';\nimport { isAwsCredentialsValid } from './awsCredentials';\nimport { getCdkAppCommand, getDockerDir } from './cdkApp';\nimport { buildRemote, resolvePublishTarget } from './remote';\nimport { deployAccountStack, deployBootstrapStack, deployDomainStack } from './stacks';\nimport { getViewsS3Destinations } from './viewsSync';\n\nconst IMAGE_TAG = 'qpq-cdk-deployer';\nconst AWS_CLI_IMAGE = 'amazon/aws-cli';\n\nconst BUILD_CONCURRENCY = Number(process.env.GO_DOCKER_BUILD_CONCURRENCY) || 4;\nconst DEPLOY_CONCURRENCY = Number(process.env.GO_DOCKER_DEPLOY_CONCURRENCY) || Infinity;\n\n// Credentials/region reach the containers via `docker run -e NAME` (value\n// inherited from this process's env, never on the docker command line).\nconst AWS_ENV_PASSTHROUGH = [\n 'AWS_ACCESS_KEY_ID',\n 'AWS_SECRET_ACCESS_KEY',\n 'AWS_SESSION_TOKEN',\n 'AWS_REGION',\n 'AWS_DEFAULT_REGION',\n 'AWS_DEFAULT_ACCOUNT',\n];\n\nconst assemblyDir = (appName: string, serviceName: string): string => path.join(getRoot(), 'dist', 'qpq', 'cdk-docker', appName, serviceName);\n\nconst assertDockerRunning = async (): Promise<void> => {\n try {\n await runCommand('docker', ['info', '--format', '\"docker daemon ok — server {{.ServerVersion}}\"']);\n } catch {\n throw new Error('Docker daemon is not running (start Docker Desktop and retry).');\n }\n};\n\nconst buildDeployerImage = async (): Promise<void> => {\n // Pin the image's CDK CLI to the CLI's own aws-cdk version so it can always\n // read the assembly schema the host synthesized.\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const cdkVersion = require('aws-cdk/package.json').version as string;\n console.log(`Building deployer image [${IMAGE_TAG}] (aws-cdk ${cdkVersion})`);\n await runCommand('docker', ['build', '-t', IMAGE_TAG, '--build-arg', `CDK_VERSION=${cdkVersion}`, getDockerDir()]);\n};\n\n// Deploy one stack from a pre-synthesized assembly in a throwaway container\n// named <service>-<stackType> (e.g. mini-web) so `docker ps` reads cleanly.\n// The assembly mounts read-only and is copied container-local first — the CDK\n// CLI writes lock files next to the assembly it reads, and the copy keeps\n// parallel api/web deploys of the same service fully isolated.\nconst dockerDeployStack = (\n color: number,\n appName: string,\n serviceName: string,\n stackType: 'inf' | 'api' | 'web',\n stackName: string,\n): Promise<void> => {\n const containerName = `${serviceName}-${stackType}`;\n return runCommandPrefixed(\n `${stackType}:${serviceName}`,\n 'docker',\n [\n // A container left behind by an interrupted run would block reusing the\n // name — clear it quietly first.\n 'rm',\n '-f',\n containerName,\n '>/dev/null',\n '2>&1',\n ';',\n 'docker',\n 'run',\n '--rm',\n '--name',\n containerName,\n '-v',\n `\"${assemblyDir(appName, serviceName)}:/assembly:ro\"`,\n ...AWS_ENV_PASSTHROUGH.flatMap((name) => ['-e', name]),\n IMAGE_TAG,\n 'bash',\n '-c',\n `\"cp -r /assembly /work/assembly && cdk deploy ${stackName} --app /work/assembly --require-approval never --progress events\"`,\n ],\n { color },\n );\n};\n\n// Sync one service's pre-built views to S3 in a throwaway aws-cli container\n// named <service>-views. The official image's entrypoint is `aws`. Multiple\n// destinations (shell → website root + views prefix) run sequentially within\n// the service, reusing the container name.\nconst dockerSyncViews = async (color: number, appName: string, serviceName: string): Promise<void> => {\n const containerName = `${serviceName}-views`;\n for (const destination of getViewsS3Destinations(appName, serviceName)) {\n await runCommandPrefixed(\n `views:${serviceName}`,\n 'docker',\n [\n 'rm',\n '-f',\n containerName,\n '>/dev/null',\n '2>&1',\n ';',\n 'docker',\n 'run',\n '--rm',\n '--name',\n containerName,\n '-v',\n `\"${getViewsDistDir(appName, serviceName)}:/views:ro\"`,\n ...AWS_ENV_PASSTHROUGH.flatMap((name) => ['-e', name]),\n AWS_CLI_IMAGE,\n 's3',\n 'sync',\n '/views',\n destination,\n ],\n { color },\n );\n }\n};\n\n// Publish one service's already-built federated remote to S3 in a throwaway\n// aws-cli container named <service>-publish. The version dir (everything the\n// manifest references) syncs first, then the manifest.json is copied last —\n// same ordering guarantee as the host-side publish, so a reading lambda never\n// sees a manifest whose files aren't all present yet. resolvePublishTarget reads\n// the manifest hash + resolved bucket/prefix from the buildRemote output.\nconst dockerPublishRemote = async (color: number, appName: string, serviceName: string): Promise<void> => {\n const { publishPath, manifestHash, bucketName, servicePrefix } = resolvePublishTarget(appName, serviceName);\n const containerName = `${serviceName}-publish`;\n\n // /publish is the service-remote-published dir; the hashed version subdir and\n // manifest.json both live directly under it.\n const s3Operations: string[][] = [\n ['s3', 'sync', `/publish/${manifestHash}`, `s3://${bucketName}/${servicePrefix}/${manifestHash}`],\n ['s3', 'cp', '/publish/manifest.json', `s3://${bucketName}/${servicePrefix}/manifest.json`],\n ];\n\n for (const s3Operation of s3Operations) {\n await runCommandPrefixed(\n `publish:${serviceName}`,\n 'docker',\n [\n 'rm',\n '-f',\n containerName,\n '>/dev/null',\n '2>&1',\n ';',\n 'docker',\n 'run',\n '--rm',\n '--name',\n containerName,\n '-v',\n `\"${publishPath}:/publish:ro\"`,\n ...AWS_ENV_PASSTHROUGH.flatMap((name) => ['-e', name]),\n AWS_CLI_IMAGE,\n ...s3Operation,\n ],\n { color },\n );\n }\n};\n\nexport const awsGoDocker = async (appName: string, plan: DeployPlan): Promise<void> => {\n if (plan.kind === 'cancelled') {\n return;\n }\n\n if ((await isAwsCredentialsValid()) === false) {\n console.log('Credentials are expired or invalid.');\n return;\n }\n\n logTimeStart('totalTime');\n\n if (plan.kind === 'account') {\n await deployAccountStack(plan.appName);\n logTimeEnd('totalTime');\n return;\n }\n\n if (plan.kind === 'bootstrap') {\n if (plan.includeDomain) {\n await deployDomainStack(plan.appName);\n }\n await deployBootstrapStack(plan.appName);\n logTimeEnd('totalTime');\n return;\n }\n\n const { services, stacks } = plan;\n\n const allStacks = stacks === 'all';\n const needInf = allStacks || stacks === 'inf';\n const needApi = allStacks || stacks === 'api';\n const needWeb = allStacks || stacks === 'web';\n const needViews = allStacks || stacks === 'views';\n const needCdkDeploys = needInf || needApi || needWeb;\n\n const viewServices = needViews ? services.filter((s) => getServiceNamesWithViews(appName).includes(s)) : [];\n\n console.log('\\n\\nRunning dockerized deploy\\n\\n');\n console.log('Executing for services');\n console.log(services.join(', '));\n\n // Federated publish needs the api stack (needApi ⇒ needCdkDeploys), so any\n // docker preflight it requires is already covered by these two checks.\n if (needCdkDeploys || viewServices.length > 0) {\n await assertDockerRunning();\n }\n if (needCdkDeploys) {\n await buildDeployerImage();\n }\n\n // ---- Phase 1: build everything locally ----\n console.log('\\n=== Phase 1: local builds ===\\n');\n\n await runAppHook(appName, 'predeploy');\n\n // Workspace packages resolve through their built dist/ (package.json main),\n // so bundles would ship stale code unless every lib is tsc'd first. npm runs\n // the workspaces in topological order; tsc -b is incremental, so this is\n // seconds when nothing changed.\n console.log('Building workspace packages');\n await runCommand('npm', ['run', 'build', '--workspaces', '--if-present']);\n\n // Synth QPQ configs (shell's config resolves the view bucket names).\n // In-process (no subprocess per service) — it's just config loads + JSON writes.\n const qpqSynthServices = [...new Set([...services, ...(needViews ? ['shell'] : [])])];\n for (const service of qpqSynthServices) {\n await synthCommand([service, '--app', appName]);\n }\n\n // Federated remotes are the backend story code, so republish them whenever the\n // api stack was (re)deployed. Skips services without defineFederatedModuleStore(...).\n // Detected here (after the workspace build) because it loads each service's config.\n const federatedServices = needApi ? getServiceNamesWithFederation(appName, services) : [];\n\n // The aws-cli image backs both the views sync (phase 4) and the federated\n // publish (phase 5) waves. Pull once now so those waves don't race N containers\n // into pulling the same image. Docker is already confirmed running above.\n if (viewServices.length > 0 || federatedServices.length > 0) {\n await runCommand('docker', ['pull', AWS_CLI_IMAGE]);\n }\n\n if (stacks !== 'views') {\n assertNoFailures(\n 'API bundling',\n await runTasks(\n services.map((service) => ({\n label: `bundle-api:${service}`,\n run: async () => {\n console.log(`Bundling api: [${service}]`);\n const qpqConfig = loadServiceQpqConfig(appName, service);\n await runRspack(getServiceRspackConfig(qpqConfig, path.join(getServiceDirectory(appName, service), 'service')));\n },\n })),\n BUILD_CONCURRENCY,\n ),\n );\n }\n\n assertNoFailures(\n 'Views bundling',\n await runTasks(\n viewServices.map((service) => ({\n label: `bundle-views:${service}`,\n run: async () => {\n console.log(`Bundling views: [${service}]`);\n await bundleViews(appName, service);\n },\n })),\n BUILD_CONCURRENCY,\n ),\n );\n\n // Build the federated remotes locally now (rspack needs the workspace), so the\n // publish wave only has to sync the already-built output — mirroring how views\n // are bundled here and synced later.\n assertNoFailures(\n 'Remote bundling',\n await runTasks(\n federatedServices.map((service) => ({\n label: `bundle-remote:${service}`,\n run: async () => {\n console.log(`Bundling federated remote: [${service}]`);\n await buildRemote(appName, service);\n },\n })),\n BUILD_CONCURRENCY,\n ),\n );\n\n if (needCdkDeploys) {\n // One self-contained cloud assembly per service (all its stacks + staged\n // assets) — separate --output dirs so synths can run in parallel and\n // containers never share mutable state.\n assertNoFailures(\n 'CDK synth',\n await runTasks(\n services.map((service) => ({\n label: `cdk-synth:${service}`,\n run: async () => {\n const outputDir = assemblyDir(appName, service);\n fs.rmSync(outputDir, { recursive: true, force: true });\n await runCommandPrefixed(\n `cdk-synth:${service}`,\n 'npx',\n ['cdk', 'synth', '--quiet', '--app', `'${getCdkAppCommand()}'`, '--output', `\"${outputDir}\"`],\n {\n cwd: getRoot(),\n env: { DEPLOY_SERVICE_NAME: service, DEPLOY_APP_NAME: appName },\n color: nextPrefixColor(),\n },\n );\n },\n })),\n BUILD_CONCURRENCY,\n ),\n );\n }\n\n // Stack names come from each service's live config, resolved once up front.\n const stackNames = new Map(\n services.map((service) => {\n const qpqConfig = loadServiceQpqConfig(appName, service);\n return [\n service,\n {\n inf: qpqDeployAwsCdkUtils.getInfStackName(qpqConfig),\n api: qpqDeployAwsCdkUtils.getApiStackName(qpqConfig),\n web: qpqDeployAwsCdkUtils.getWebStackName(qpqConfig),\n },\n ];\n }),\n );\n\n // ---- Phase 2: inf stacks, one container per service, all concurrent ----\n if (needInf) {\n console.log('\\n=== Phase 2: deploy inf stacks (docker) ===\\n');\n logTimeStart('infWave');\n assertNoFailures(\n 'Inf deploy',\n await runTasks(\n services.map((service) => ({\n label: `inf:${service}`,\n run: () => dockerDeployStack(nextPrefixColor(), appName, service, 'inf', stackNames.get(service)!.inf),\n })),\n DEPLOY_CONCURRENCY,\n ),\n );\n logTimeEnd('infWave');\n }\n\n // ---- Phase 3: api + web stacks, all concurrent ----\n if (needApi || needWeb) {\n console.log('\\n=== Phase 3: deploy api + web stacks (docker) ===\\n');\n logTimeStart('apiWebWave');\n assertNoFailures(\n 'Api/Web deploy',\n await runTasks(\n (['api', 'web'] as const)\n .filter((stackType) => (stackType === 'api' ? needApi : needWeb))\n .flatMap((stackType) =>\n services.map((service) => ({\n label: `${stackType}:${service}`,\n run: () => dockerDeployStack(nextPrefixColor(), appName, service, stackType, stackNames.get(service)![stackType]),\n })),\n ),\n DEPLOY_CONCURRENCY,\n ),\n );\n logTimeEnd('apiWebWave');\n }\n\n // ---- Phase 4: sync the pre-built views to S3, all concurrent ----\n if (viewServices.length > 0) {\n console.log('\\n=== Phase 4: sync views to S3 (docker) ===\\n');\n logTimeStart('viewsWave');\n assertNoFailures(\n 'Views sync',\n await runTasks(\n viewServices.map((service) => ({\n label: `views:${service}`,\n run: () => dockerSyncViews(nextPrefixColor(), appName, service),\n })),\n DEPLOY_CONCURRENCY,\n ),\n );\n logTimeEnd('viewsWave');\n }\n\n // ---- Phase 5: publish the pre-built federated remotes to S3, all concurrent ----\n if (federatedServices.length > 0) {\n console.log('\\n=== Phase 5: publish federated remotes to S3 (docker) ===\\n');\n logTimeStart('publishWave');\n assertNoFailures(\n 'Federated publish',\n await runTasks(\n federatedServices.map((service) => ({\n label: `publish:${service}`,\n run: () => dockerPublishRemote(nextPrefixColor(), appName, service),\n })),\n DEPLOY_CONCURRENCY,\n ),\n );\n logTimeEnd('publishWave');\n }\n\n logTimeEnd('totalTime');\n};\n"]}
|
|
1
|
+
{"version":3,"file":"goDocker.js","sourceRoot":"","sources":["../../../../src/platforms/aws/goDocker.ts"],"names":[],"mappings":"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","sourcesContent":["// `qpq go:docker` — asks the same questions as `qpq go`, then deploys in\n// parallel via docker instead of sequentially:\n//\n// 1. Build everything locally first: QPQ config synth, rspack API bundles,\n// rspack view bundles, rspack federated-remote bundles, and one\n// self-contained CDK cloud assembly per service\n// (`cdk synth --output dist/qpq/cdk-docker/<app>/<service>`).\n// 2. Wave 1 (inf): one docker container per service deploys its inf stack,\n// all concurrently. Containers run only the CDK CLI against the mounted\n// pre-synthesized assembly — the workspace (and its npm-linked\n// quidproquo packages) never needs to exist inside the image.\n// 3. Wave 2 (api + web): once every inf stack is done, api and web stacks\n// for all services deploy concurrently (they depend only on inf, not on\n// each other).\n// 4. Views: the already-built bundles are synced to S3, one aws-cli\n// container per service, all concurrently.\n// 5. Publish: the already-built federated remotes (backends that opt in with\n// defineFederatedModuleStore(...)) are synced to S3 and their manifests\n// flipped, one aws-cli container per service, all concurrently.\n//\n// domain/bootstrap menu options deploy host-side exactly like `qpq go` —\n// a single stack gains nothing from docker.\n//\n// Requires the same env as `go` plus a running docker daemon. Knobs:\n// GO_DOCKER_BUILD_CONCURRENCY (default 4 — local builds are CPU-bound) and\n// GO_DOCKER_DEPLOY_CONCURRENCY (default unlimited — deploys just wait on\n// CloudFormation).\nimport { qpqDeployAwsCdkUtils } from 'quidproquo-deploy-awscdk';\nimport { getServiceRspackConfig } from 'quidproquo-deploy-rspack';\n\nimport fs from 'fs';\nimport path from 'path';\n\nimport { synthCommand } from '../../commands/synth';\nimport { DeployPlan } from '../../lib/deployPrompts';\nimport { getRoot, getServiceDirectory, getServiceNamesWithViews } from '../../lib/discovery';\nimport { runAppHook } from '../../lib/hooks';\nimport { getServiceNamesWithFederation, loadServiceQpqConfig } from '../../lib/qpqConfigs';\nimport { runRspack } from '../../lib/rspackRun';\nimport { nextPrefixColor, runCommand, runCommandBestEffort, runCommandPrefixed } from '../../lib/runCommand';\nimport { assertNoFailures, runTasks } from '../../lib/runTasks';\nimport { logTimeEnd, logTimeStart } from '../../lib/timing';\nimport { bundleViews, getViewsDistDir } from '../../lib/views';\nimport { isAwsCredentialsValid } from './awsCredentials';\nimport { getCdkAppCommand, getDockerDir } from './cdkApp';\nimport { buildRemote, resolvePublishTarget } from './remote';\nimport { deployAccountStack, deployBootstrapStack, deployDomainStack } from './stacks';\nimport { getViewsS3Destinations } from './viewsSync';\n\nconst IMAGE_TAG = 'qpq-cdk-deployer';\nconst AWS_CLI_IMAGE = 'amazon/aws-cli';\n\nconst BUILD_CONCURRENCY = Number(process.env.GO_DOCKER_BUILD_CONCURRENCY) || 4;\nconst DEPLOY_CONCURRENCY = Number(process.env.GO_DOCKER_DEPLOY_CONCURRENCY) || Infinity;\n\n// Credentials/region reach the containers via `docker run -e NAME` (value\n// inherited from this process's env, never on the docker command line).\nconst AWS_ENV_PASSTHROUGH = [\n 'AWS_ACCESS_KEY_ID',\n 'AWS_SECRET_ACCESS_KEY',\n 'AWS_SESSION_TOKEN',\n 'AWS_REGION',\n 'AWS_DEFAULT_REGION',\n 'AWS_DEFAULT_ACCOUNT',\n];\n\nconst assemblyDir = (appName: string, serviceName: string): string => path.join(getRoot(), 'dist', 'qpq', 'cdk-docker', appName, serviceName);\n\n// A container left behind by an interrupted run would block reusing its name.\n// Clear it first, best-effort: a missing container (exit 1) must not fail the\n// deploy. Was a `docker rm -f … >/dev/null 2>&1 ;` prefix on the run command,\n// but that only worked under `shell: true`; as a separate call it's shell-free.\nconst removeContainer = (containerName: string): Promise<void> => runCommandBestEffort('docker', ['rm', '-f', containerName]);\n\nconst assertDockerRunning = async (): Promise<void> => {\n try {\n await runCommand('docker', ['info', '--format', 'docker daemon ok — server {{.ServerVersion}}']);\n } catch {\n throw new Error('Docker daemon is not running (start Docker Desktop and retry).');\n }\n};\n\nconst buildDeployerImage = async (): Promise<void> => {\n // Pin the image's CDK CLI to the CLI's own aws-cdk version so it can always\n // read the assembly schema the host synthesized.\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const cdkVersion = require('aws-cdk/package.json').version as string;\n console.log(`Building deployer image [${IMAGE_TAG}] (aws-cdk ${cdkVersion})`);\n await runCommand('docker', ['build', '-t', IMAGE_TAG, '--build-arg', `CDK_VERSION=${cdkVersion}`, getDockerDir()]);\n};\n\n// Deploy one stack from a pre-synthesized assembly in a throwaway container\n// named <service>-<stackType> (e.g. mini-web) so `docker ps` reads cleanly.\n// The assembly mounts read-only and is copied container-local first — the CDK\n// CLI writes lock files next to the assembly it reads, and the copy keeps\n// parallel api/web deploys of the same service fully isolated.\nconst dockerDeployStack = async (\n color: number,\n appName: string,\n serviceName: string,\n stackType: 'inf' | 'api' | 'web',\n stackName: string,\n): Promise<void> => {\n const containerName = `${serviceName}-${stackType}`;\n await removeContainer(containerName);\n await runCommandPrefixed(\n `${stackType}:${serviceName}`,\n 'docker',\n [\n 'run',\n '--rm',\n '--name',\n containerName,\n '-v',\n `${assemblyDir(appName, serviceName)}:/assembly:ro`,\n ...AWS_ENV_PASSTHROUGH.flatMap((name) => ['-e', name]),\n IMAGE_TAG,\n 'bash',\n '-c',\n `cp -r /assembly /work/assembly && cdk deploy ${stackName} --app /work/assembly --require-approval never --progress events`,\n ],\n { color },\n );\n};\n\n// Sync one service's pre-built views to S3 in a throwaway aws-cli container\n// named <service>-views. The official image's entrypoint is `aws`. Multiple\n// destinations (shell → website root + views prefix) run sequentially within\n// the service, reusing the container name.\nconst dockerSyncViews = async (color: number, appName: string, serviceName: string): Promise<void> => {\n const containerName = `${serviceName}-views`;\n for (const destination of getViewsS3Destinations(appName, serviceName)) {\n await removeContainer(containerName);\n await runCommandPrefixed(\n `views:${serviceName}`,\n 'docker',\n [\n 'run',\n '--rm',\n '--name',\n containerName,\n '-v',\n `${getViewsDistDir(appName, serviceName)}:/views:ro`,\n ...AWS_ENV_PASSTHROUGH.flatMap((name) => ['-e', name]),\n AWS_CLI_IMAGE,\n 's3',\n 'sync',\n '/views',\n destination,\n ],\n { color },\n );\n }\n};\n\n// Publish one service's already-built federated remote to S3 in a throwaway\n// aws-cli container named <service>-publish. The version dir (everything the\n// manifest references) syncs first, then the manifest.json is copied last —\n// same ordering guarantee as the host-side publish, so a reading lambda never\n// sees a manifest whose files aren't all present yet. resolvePublishTarget reads\n// the manifest hash + resolved bucket/prefix from the buildRemote output.\nconst dockerPublishRemote = async (color: number, appName: string, serviceName: string): Promise<void> => {\n const { publishPath, manifestHash, bucketName, servicePrefix } = resolvePublishTarget(appName, serviceName);\n const containerName = `${serviceName}-publish`;\n\n // /publish is the service-remote-published dir; the hashed version subdir and\n // manifest.json both live directly under it.\n const s3Operations: string[][] = [\n ['s3', 'sync', `/publish/${manifestHash}`, `s3://${bucketName}/${servicePrefix}/${manifestHash}`],\n ['s3', 'cp', '/publish/manifest.json', `s3://${bucketName}/${servicePrefix}/manifest.json`],\n ];\n\n for (const s3Operation of s3Operations) {\n await removeContainer(containerName);\n await runCommandPrefixed(\n `publish:${serviceName}`,\n 'docker',\n [\n 'run',\n '--rm',\n '--name',\n containerName,\n '-v',\n `${publishPath}:/publish:ro`,\n ...AWS_ENV_PASSTHROUGH.flatMap((name) => ['-e', name]),\n AWS_CLI_IMAGE,\n ...s3Operation,\n ],\n { color },\n );\n }\n};\n\nexport const awsGoDocker = async (appName: string, plan: DeployPlan): Promise<void> => {\n if (plan.kind === 'cancelled') {\n return;\n }\n\n if ((await isAwsCredentialsValid()) === false) {\n console.log('Credentials are expired or invalid.');\n return;\n }\n\n logTimeStart('totalTime');\n\n if (plan.kind === 'account') {\n await deployAccountStack(plan.appName);\n logTimeEnd('totalTime');\n return;\n }\n\n if (plan.kind === 'bootstrap') {\n if (plan.includeDomain) {\n await deployDomainStack(plan.appName);\n }\n await deployBootstrapStack(plan.appName);\n logTimeEnd('totalTime');\n return;\n }\n\n const { services, stacks } = plan;\n\n const allStacks = stacks === 'all';\n const needInf = allStacks || stacks === 'inf';\n const needApi = allStacks || stacks === 'api';\n const needWeb = allStacks || stacks === 'web';\n const needViews = allStacks || stacks === 'views';\n const needCdkDeploys = needInf || needApi || needWeb;\n\n const viewServices = needViews ? services.filter((s) => getServiceNamesWithViews(appName).includes(s)) : [];\n\n console.log('\\n\\nRunning dockerized deploy\\n\\n');\n console.log('Executing for services');\n console.log(services.join(', '));\n\n // Federated publish needs the api stack (needApi ⇒ needCdkDeploys), so any\n // docker preflight it requires is already covered by these two checks.\n if (needCdkDeploys || viewServices.length > 0) {\n await assertDockerRunning();\n }\n if (needCdkDeploys) {\n await buildDeployerImage();\n }\n\n // ---- Phase 1: build everything locally ----\n console.log('\\n=== Phase 1: local builds ===\\n');\n\n await runAppHook(appName, 'predeploy');\n\n // Workspace packages resolve through their built dist/ (package.json main),\n // so bundles would ship stale code unless every lib is tsc'd first. npm runs\n // the workspaces in topological order; tsc -b is incremental, so this is\n // seconds when nothing changed.\n console.log('Building workspace packages');\n await runCommand('npm', ['run', 'build', '--workspaces', '--if-present']);\n\n // Synth QPQ configs (shell's config resolves the view bucket names).\n // In-process (no subprocess per service) — it's just config loads + JSON writes.\n const qpqSynthServices = [...new Set([...services, ...(needViews ? ['shell'] : [])])];\n for (const service of qpqSynthServices) {\n await synthCommand([service, '--app', appName]);\n }\n\n // Federated remotes are the backend story code, so republish them whenever the\n // api stack was (re)deployed. Skips services without defineFederatedModuleStore(...).\n // Detected here (after the workspace build) because it loads each service's config.\n const federatedServices = needApi ? getServiceNamesWithFederation(appName, services) : [];\n\n // The aws-cli image backs both the views sync (phase 4) and the federated\n // publish (phase 5) waves. Pull once now so those waves don't race N containers\n // into pulling the same image. Docker is already confirmed running above.\n if (viewServices.length > 0 || federatedServices.length > 0) {\n await runCommand('docker', ['pull', AWS_CLI_IMAGE]);\n }\n\n if (stacks !== 'views') {\n assertNoFailures(\n 'API bundling',\n await runTasks(\n services.map((service) => ({\n label: `bundle-api:${service}`,\n run: async () => {\n console.log(`Bundling api: [${service}]`);\n const qpqConfig = loadServiceQpqConfig(appName, service);\n await runRspack(getServiceRspackConfig(qpqConfig, path.join(getServiceDirectory(appName, service), 'service')));\n },\n })),\n BUILD_CONCURRENCY,\n ),\n );\n }\n\n assertNoFailures(\n 'Views bundling',\n await runTasks(\n viewServices.map((service) => ({\n label: `bundle-views:${service}`,\n run: async () => {\n console.log(`Bundling views: [${service}]`);\n await bundleViews(appName, service);\n },\n })),\n BUILD_CONCURRENCY,\n ),\n );\n\n // Build the federated remotes locally now (rspack needs the workspace), so the\n // publish wave only has to sync the already-built output — mirroring how views\n // are bundled here and synced later.\n assertNoFailures(\n 'Remote bundling',\n await runTasks(\n federatedServices.map((service) => ({\n label: `bundle-remote:${service}`,\n run: async () => {\n console.log(`Bundling federated remote: [${service}]`);\n await buildRemote(appName, service);\n },\n })),\n BUILD_CONCURRENCY,\n ),\n );\n\n if (needCdkDeploys) {\n // One self-contained cloud assembly per service (all its stacks + staged\n // assets) — separate --output dirs so synths can run in parallel and\n // containers never share mutable state.\n assertNoFailures(\n 'CDK synth',\n await runTasks(\n services.map((service) => ({\n label: `cdk-synth:${service}`,\n run: async () => {\n const outputDir = assemblyDir(appName, service);\n fs.rmSync(outputDir, { recursive: true, force: true });\n await runCommandPrefixed(`cdk-synth:${service}`, 'npx', ['cdk', 'synth', '--quiet', '--app', getCdkAppCommand(), '--output', outputDir], {\n cwd: getRoot(),\n env: { DEPLOY_SERVICE_NAME: service, DEPLOY_APP_NAME: appName },\n color: nextPrefixColor(),\n });\n },\n })),\n BUILD_CONCURRENCY,\n ),\n );\n }\n\n // Stack names come from each service's live config, resolved once up front.\n const stackNames = new Map(\n services.map((service) => {\n const qpqConfig = loadServiceQpqConfig(appName, service);\n return [\n service,\n {\n inf: qpqDeployAwsCdkUtils.getInfStackName(qpqConfig),\n api: qpqDeployAwsCdkUtils.getApiStackName(qpqConfig),\n web: qpqDeployAwsCdkUtils.getWebStackName(qpqConfig),\n },\n ];\n }),\n );\n\n // ---- Phase 2: inf stacks, one container per service, all concurrent ----\n if (needInf) {\n console.log('\\n=== Phase 2: deploy inf stacks (docker) ===\\n');\n logTimeStart('infWave');\n assertNoFailures(\n 'Inf deploy',\n await runTasks(\n services.map((service) => ({\n label: `inf:${service}`,\n run: () => dockerDeployStack(nextPrefixColor(), appName, service, 'inf', stackNames.get(service)!.inf),\n })),\n DEPLOY_CONCURRENCY,\n ),\n );\n logTimeEnd('infWave');\n }\n\n // ---- Phase 3: api + web stacks, all concurrent ----\n if (needApi || needWeb) {\n console.log('\\n=== Phase 3: deploy api + web stacks (docker) ===\\n');\n logTimeStart('apiWebWave');\n assertNoFailures(\n 'Api/Web deploy',\n await runTasks(\n (['api', 'web'] as const)\n .filter((stackType) => (stackType === 'api' ? needApi : needWeb))\n .flatMap((stackType) =>\n services.map((service) => ({\n label: `${stackType}:${service}`,\n run: () => dockerDeployStack(nextPrefixColor(), appName, service, stackType, stackNames.get(service)![stackType]),\n })),\n ),\n DEPLOY_CONCURRENCY,\n ),\n );\n logTimeEnd('apiWebWave');\n }\n\n // ---- Phase 4: sync the pre-built views to S3, all concurrent ----\n if (viewServices.length > 0) {\n console.log('\\n=== Phase 4: sync views to S3 (docker) ===\\n');\n logTimeStart('viewsWave');\n assertNoFailures(\n 'Views sync',\n await runTasks(\n viewServices.map((service) => ({\n label: `views:${service}`,\n run: () => dockerSyncViews(nextPrefixColor(), appName, service),\n })),\n DEPLOY_CONCURRENCY,\n ),\n );\n logTimeEnd('viewsWave');\n }\n\n // ---- Phase 5: publish the pre-built federated remotes to S3, all concurrent ----\n if (federatedServices.length > 0) {\n console.log('\\n=== Phase 5: publish federated remotes to S3 (docker) ===\\n');\n logTimeStart('publishWave');\n assertNoFailures(\n 'Federated publish',\n await runTasks(\n federatedServices.map((service) => ({\n label: `publish:${service}`,\n run: () => dockerPublishRemote(nextPrefixColor(), appName, service),\n })),\n DEPLOY_CONCURRENCY,\n ),\n );\n logTimeEnd('publishWave');\n }\n\n logTimeEnd('totalTime');\n};\n"]}
|
|
@@ -84,6 +84,11 @@ export const cliCommands = [
|
|
|
84
84
|
summary: 'Flip manifests to the uploaded versions',
|
|
85
85
|
run: (a) => require('../commands/publish').publishDeployCommand(a),
|
|
86
86
|
},
|
|
87
|
+
{
|
|
88
|
+
name: 'check:circular',
|
|
89
|
+
summary: 'Scan workspace sources for circular imports (fails on cycles; --warn to only report)',
|
|
90
|
+
run: (a) => require('../commands/checkCircular').checkCircularCommand(a),
|
|
91
|
+
},
|
|
87
92
|
{
|
|
88
93
|
name: 'hooks',
|
|
89
94
|
usageArgs: '<name>',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commandRegistry.js","sourceRoot":"","sources":["../../../src/cli/commandRegistry.ts"],"names":[],"mappings":"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","sourcesContent":["// Single source of truth for every qpq command: its name, the one-line\n// summary (shared by `qpq help` and the interactive menu) and a runner.\n//\n// Command modules are required lazily inside each runner so a simple\n// `qpq help` doesn't pay for the whole toolchain, and so ts-node can be\n// registered before any command module (or anything it requires) loads.\nimport { promptText } from '../lib/prompts';\n\nexport type CliCommand = {\n name: string;\n // Argument hint shown in the usage text, e.g. '[svc] [stack]'.\n usageArgs?: string;\n summary: string;\n // Extra usage-only detail lines, indented under the summary.\n usageExtra?: string[];\n // Menu-only: commands that need a positional argument (which the menu has\n // no argv to carry) gather it here before running.\n promptArgs?: () => Promise<string[]>;\n run: (commandArgv: string[]) => Promise<void>;\n};\n\n// `qpq hooks` needs a hook name; when launched from the menu there is no\n// argv to pass it in, so ask.\nconst promptHookName = async (): Promise<string[]> => [\n await promptText('Hook name (runs qpq:<name>, or plain <name>, in every app/package that defines it):'),\n];\n\n/* eslint-disable @typescript-eslint/no-require-imports */\nexport const cliCommands: CliCommand[] = [\n {\n name: 'go',\n usageArgs: '[svc] [stack]',\n summary: 'Deploy services (interactive; platform from deploy.config.json, default aws).',\n usageExtra: [\n 'Pass positional args to skip prompts, e.g. qpq go all all — svc is',\n \"'all' | comma-list | account | domain | bootstrap; stack is all|inf|api|web|views.\",\n \"A full 'all all' (or 'all api') deploy also publishes federated backends.\",\n ],\n run: (a) => require('../commands/go').goCommand(a),\n },\n {\n name: 'go:docker',\n summary: 'Same as go (incl. positional args), but deploys in parallel via docker',\n run: (a) => require('../commands/goDocker').goDockerCommand(a),\n },\n {\n name: 'go:dev',\n summary: 'Run the full local dev stack (api + web) in one process',\n run: (a) => require('../commands/goDev').goDevCommand(a),\n },\n {\n name: 'go:dev:api',\n summary: 'Run the local API dev server (hot reload)',\n run: (a) => require('../commands/goDevApi').goDevApiCommand(a),\n },\n {\n name: 'go:dev:web',\n summary: 'Run every views microfrontend dev server',\n run: (a) => require('../commands/goDevWeb').goDevWebCommand(a),\n },\n {\n name: 'teardown',\n summary: 'Destroy web/api/inf stacks for selected services (interactive)',\n run: (a) => require('../commands/teardown').teardownCommand(a),\n },\n {\n name: 'clear-resources',\n summary: 'Empty selected buckets/tables (data only, stacks untouched; interactive)',\n run: (a) => require('../commands/clearResources').clearResourcesCommand(a),\n },\n {\n name: 'synth',\n usageArgs: '[service]',\n summary: 'Synth QPQ configs to dist/apps/<app>/infrastructure',\n run: (a) => require('../commands/synth').synthCommand(a),\n },\n {\n name: 'prep',\n summary: 'Regenerate apps/<app>/tsconfig.federated.json',\n run: (a) => require('../commands/prep').prepCommand(a),\n },\n {\n name: 'publish',\n summary: 'Build + upload + deploy federated remotes',\n run: (a) => require('../commands/publish').publishCommand(a),\n },\n {\n name: 'publish:build',\n summary: 'Build federated remotes locally',\n run: (a) => require('../commands/publish').publishBuildCommand(a),\n },\n {\n name: 'publish:upload',\n summary: 'Upload built version dirs (nothing goes live)',\n run: (a) => require('../commands/publish').publishUploadCommand(a),\n },\n {\n name: 'publish:deploy',\n summary: 'Flip manifests to the uploaded versions',\n run: (a) => require('../commands/publish').publishDeployCommand(a),\n },\n {\n name: 'hooks',\n usageArgs: '<name>',\n summary: 'Run qpq:<name> (or plain <name>) in every app/package that defines it (dependency ordered, parallel; --jobs=N)',\n promptArgs: promptHookName,\n run: (a) => require('../commands/hooks').hooksCommand(a),\n },\n];\n/* eslint-enable @typescript-eslint/no-require-imports */\n\n// Width of the \"name [args]\" column in the usage text.\nconst usageColumnWidth = 17;\n\nexport const buildUsage = (): string => {\n const commandLines = cliCommands.flatMap((command) => {\n const nameAndArgs = command.usageArgs ? `${command.name} ${command.usageArgs}` : command.name;\n const extraLines = (command.usageExtra ?? []).map((line) => ` ${''.padEnd(usageColumnWidth)}${line}`);\n return [` ${nameAndArgs.padEnd(usageColumnWidth)}${command.summary}`, ...extraLines];\n });\n\n return [\n 'qpq — build, dev and deploy orchestration for QPQ apps',\n '',\n 'Usage: qpq <command> [--app <name>] [--env <name>] [--platform <name>]',\n ' qpq (no command opens an interactive menu)',\n '',\n 'Commands:',\n ...commandLines,\n '',\n ].join('\\n');\n};\n"]}
|
|
1
|
+
{"version":3,"file":"commandRegistry.js","sourceRoot":"","sources":["../../../src/cli/commandRegistry.ts"],"names":[],"mappings":"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","sourcesContent":["// Single source of truth for every qpq command: its name, the one-line\n// summary (shared by `qpq help` and the interactive menu) and a runner.\n//\n// Command modules are required lazily inside each runner so a simple\n// `qpq help` doesn't pay for the whole toolchain, and so ts-node can be\n// registered before any command module (or anything it requires) loads.\nimport { promptText } from '../lib/prompts';\n\nexport type CliCommand = {\n name: string;\n // Argument hint shown in the usage text, e.g. '[svc] [stack]'.\n usageArgs?: string;\n summary: string;\n // Extra usage-only detail lines, indented under the summary.\n usageExtra?: string[];\n // Menu-only: commands that need a positional argument (which the menu has\n // no argv to carry) gather it here before running.\n promptArgs?: () => Promise<string[]>;\n run: (commandArgv: string[]) => Promise<void>;\n};\n\n// `qpq hooks` needs a hook name; when launched from the menu there is no\n// argv to pass it in, so ask.\nconst promptHookName = async (): Promise<string[]> => [\n await promptText('Hook name (runs qpq:<name>, or plain <name>, in every app/package that defines it):'),\n];\n\n/* eslint-disable @typescript-eslint/no-require-imports */\nexport const cliCommands: CliCommand[] = [\n {\n name: 'go',\n usageArgs: '[svc] [stack]',\n summary: 'Deploy services (interactive; platform from deploy.config.json, default aws).',\n usageExtra: [\n 'Pass positional args to skip prompts, e.g. qpq go all all — svc is',\n \"'all' | comma-list | account | domain | bootstrap; stack is all|inf|api|web|views.\",\n \"A full 'all all' (or 'all api') deploy also publishes federated backends.\",\n ],\n run: (a) => require('../commands/go').goCommand(a),\n },\n {\n name: 'go:docker',\n summary: 'Same as go (incl. positional args), but deploys in parallel via docker',\n run: (a) => require('../commands/goDocker').goDockerCommand(a),\n },\n {\n name: 'go:dev',\n summary: 'Run the full local dev stack (api + web) in one process',\n run: (a) => require('../commands/goDev').goDevCommand(a),\n },\n {\n name: 'go:dev:api',\n summary: 'Run the local API dev server (hot reload)',\n run: (a) => require('../commands/goDevApi').goDevApiCommand(a),\n },\n {\n name: 'go:dev:web',\n summary: 'Run every views microfrontend dev server',\n run: (a) => require('../commands/goDevWeb').goDevWebCommand(a),\n },\n {\n name: 'teardown',\n summary: 'Destroy web/api/inf stacks for selected services (interactive)',\n run: (a) => require('../commands/teardown').teardownCommand(a),\n },\n {\n name: 'clear-resources',\n summary: 'Empty selected buckets/tables (data only, stacks untouched; interactive)',\n run: (a) => require('../commands/clearResources').clearResourcesCommand(a),\n },\n {\n name: 'synth',\n usageArgs: '[service]',\n summary: 'Synth QPQ configs to dist/apps/<app>/infrastructure',\n run: (a) => require('../commands/synth').synthCommand(a),\n },\n {\n name: 'prep',\n summary: 'Regenerate apps/<app>/tsconfig.federated.json',\n run: (a) => require('../commands/prep').prepCommand(a),\n },\n {\n name: 'publish',\n summary: 'Build + upload + deploy federated remotes',\n run: (a) => require('../commands/publish').publishCommand(a),\n },\n {\n name: 'publish:build',\n summary: 'Build federated remotes locally',\n run: (a) => require('../commands/publish').publishBuildCommand(a),\n },\n {\n name: 'publish:upload',\n summary: 'Upload built version dirs (nothing goes live)',\n run: (a) => require('../commands/publish').publishUploadCommand(a),\n },\n {\n name: 'publish:deploy',\n summary: 'Flip manifests to the uploaded versions',\n run: (a) => require('../commands/publish').publishDeployCommand(a),\n },\n {\n name: 'check:circular',\n summary: 'Scan workspace sources for circular imports (fails on cycles; --warn to only report)',\n run: (a) => require('../commands/checkCircular').checkCircularCommand(a),\n },\n {\n name: 'hooks',\n usageArgs: '<name>',\n summary: 'Run qpq:<name> (or plain <name>) in every app/package that defines it (dependency ordered, parallel; --jobs=N)',\n promptArgs: promptHookName,\n run: (a) => require('../commands/hooks').hooksCommand(a),\n },\n];\n/* eslint-enable @typescript-eslint/no-require-imports */\n\n// Width of the \"name [args]\" column in the usage text.\nconst usageColumnWidth = 17;\n\nexport const buildUsage = (): string => {\n const commandLines = cliCommands.flatMap((command) => {\n const nameAndArgs = command.usageArgs ? `${command.name} ${command.usageArgs}` : command.name;\n const extraLines = (command.usageExtra ?? []).map((line) => ` ${''.padEnd(usageColumnWidth)}${line}`);\n return [` ${nameAndArgs.padEnd(usageColumnWidth)}${command.summary}`, ...extraLines];\n });\n\n return [\n 'qpq — build, dev and deploy orchestration for QPQ apps',\n '',\n 'Usage: qpq <command> [--app <name>] [--env <name>] [--platform <name>]',\n ' qpq (no command opens an interactive menu)',\n '',\n 'Commands:',\n ...commandLines,\n '',\n ].join('\\n');\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const checkCircularCommand: (argv: string[]) => Promise<void>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// `qpq check:circular` — scan every workspace's src for circular imports (the
|
|
2
|
+
// class of bug that TDZ-crashes ESM bundles and silently drops exports under
|
|
3
|
+
// CJS). Cycles fail the command (exit 1) — they are never acceptable; --warn or
|
|
4
|
+
// QPQ_CIRCULAR_DEPS_WARN=1 is a temporary escape hatch that reports without
|
|
5
|
+
// failing while fixing.
|
|
6
|
+
import { findWorkspaceImportCycles } from '../lib/circularImports';
|
|
7
|
+
import { getRoot } from '../lib/discovery';
|
|
8
|
+
// madge reports every distinct loop path; one tangled module can produce dozens
|
|
9
|
+
// of chains through the same files. Merge chains that share any file into one
|
|
10
|
+
// group so the report shows each tangle once, with its full blast radius.
|
|
11
|
+
const groupCycles = (cycles) => {
|
|
12
|
+
const parent = new Map();
|
|
13
|
+
const find = (file) => {
|
|
14
|
+
const found = parent.get(file) ?? file;
|
|
15
|
+
if (found === file) {
|
|
16
|
+
return file;
|
|
17
|
+
}
|
|
18
|
+
const rootFile = find(found);
|
|
19
|
+
parent.set(file, rootFile);
|
|
20
|
+
return rootFile;
|
|
21
|
+
};
|
|
22
|
+
for (const cycle of cycles) {
|
|
23
|
+
for (const file of cycle) {
|
|
24
|
+
parent.set(find(file), find(cycle[0]));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const groups = new Map();
|
|
28
|
+
for (const cycle of cycles) {
|
|
29
|
+
const key = find(cycle[0]);
|
|
30
|
+
const group = groups.get(key) ?? { files: [], chainCount: 0 };
|
|
31
|
+
group.chainCount += 1;
|
|
32
|
+
group.files = [...new Set([...group.files, ...cycle])];
|
|
33
|
+
groups.set(key, group);
|
|
34
|
+
}
|
|
35
|
+
return [...groups.values()];
|
|
36
|
+
};
|
|
37
|
+
export const checkCircularCommand = async (argv) => {
|
|
38
|
+
const warnOnly = argv.includes('--warn') || !!process.env.QPQ_CIRCULAR_DEPS_WARN;
|
|
39
|
+
const cycles = await findWorkspaceImportCycles(getRoot());
|
|
40
|
+
if (cycles.length === 0) {
|
|
41
|
+
console.log('check:circular: no circular imports found');
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const groups = groupCycles(cycles);
|
|
45
|
+
const colour = warnOnly ? '\x1b[33m' : '\x1b[31m';
|
|
46
|
+
for (const group of groups) {
|
|
47
|
+
const chainNote = group.chainCount > 1 ? `, ${group.chainCount} distinct loops` : '';
|
|
48
|
+
console.warn(`${colour}Circular imports (${group.files.length} files${chainNote}):\n ${group.files.join('\n ')}\x1b[0m`);
|
|
49
|
+
}
|
|
50
|
+
console.warn(`${colour}check:circular: ${groups.length} circular import group(s) found (${cycles.length} loops)\x1b[0m`);
|
|
51
|
+
if (!warnOnly) {
|
|
52
|
+
process.exitCode = 1;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=checkCircular.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkCircular.js","sourceRoot":"","sources":["../../../src/commands/checkCircular.ts"],"names":[],"mappings":"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","sourcesContent":["// `qpq check:circular` — scan every workspace's src for circular imports (the\n// class of bug that TDZ-crashes ESM bundles and silently drops exports under\n// CJS). Cycles fail the command (exit 1) — they are never acceptable; --warn or\n// QPQ_CIRCULAR_DEPS_WARN=1 is a temporary escape hatch that reports without\n// failing while fixing.\nimport { findWorkspaceImportCycles, ImportCycle } from '../lib/circularImports';\nimport { getRoot } from '../lib/discovery';\n\ntype CycleGroup = { files: string[]; chainCount: number };\n\n// madge reports every distinct loop path; one tangled module can produce dozens\n// of chains through the same files. Merge chains that share any file into one\n// group so the report shows each tangle once, with its full blast radius.\nconst groupCycles = (cycles: ImportCycle[]): CycleGroup[] => {\n const parent = new Map<string, string>();\n\n const find = (file: string): string => {\n const found = parent.get(file) ?? file;\n if (found === file) {\n return file;\n }\n const rootFile = find(found);\n parent.set(file, rootFile);\n return rootFile;\n };\n\n for (const cycle of cycles) {\n for (const file of cycle) {\n parent.set(find(file), find(cycle[0]));\n }\n }\n\n const groups = new Map<string, CycleGroup>();\n for (const cycle of cycles) {\n const key = find(cycle[0]);\n const group = groups.get(key) ?? { files: [], chainCount: 0 };\n group.chainCount += 1;\n group.files = [...new Set([...group.files, ...cycle])];\n groups.set(key, group);\n }\n\n return [...groups.values()];\n};\n\nexport const checkCircularCommand = async (argv: string[]): Promise<void> => {\n const warnOnly = argv.includes('--warn') || !!process.env.QPQ_CIRCULAR_DEPS_WARN;\n\n const cycles = await findWorkspaceImportCycles(getRoot());\n\n if (cycles.length === 0) {\n console.log('check:circular: no circular imports found');\n return;\n }\n\n const groups = groupCycles(cycles);\n\n const colour = warnOnly ? '\\x1b[33m' : '\\x1b[31m';\n for (const group of groups) {\n const chainNote = group.chainCount > 1 ? `, ${group.chainCount} distinct loops` : '';\n console.warn(`${colour}Circular imports (${group.files.length} files${chainNote}):\\n ${group.files.join('\\n ')}\\x1b[0m`);\n }\n console.warn(`${colour}check:circular: ${groups.length} circular import group(s) found (${cycles.length} loops)\\x1b[0m`);\n\n if (!warnOnly) {\n process.exitCode = 1;\n }\n};\n"]}
|
|
@@ -48,7 +48,18 @@ export const synthCommand = async (argv) => {
|
|
|
48
48
|
// invoked inside a deploy they're already primed; standalone synth primes
|
|
49
49
|
// them from deploy.config.json (development default).
|
|
50
50
|
primeDeployEnvFromConfig(appName);
|
|
51
|
-
|
|
51
|
+
// Validate a specified service against the app's discovered services before it
|
|
52
|
+
// reaches loadServiceQpqConfig -> require. The bare-service-name branch above
|
|
53
|
+
// already checks this; the --app/env branch used to skip it, letting a typo hit
|
|
54
|
+
// a cryptic module-resolution error and a `../` value normalize into an arbitrary
|
|
55
|
+
// require target. Both paths now validate identically.
|
|
56
|
+
const appServices = getServiceNamesWithSubdir(appName, 'service');
|
|
57
|
+
if (specifiedServiceName && !appServices.includes(specifiedServiceName)) {
|
|
58
|
+
console.error(`Service '${specifiedServiceName}' not found in app '${appName}'`);
|
|
59
|
+
process.exitCode = 1;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const serviceNames = specifiedServiceName ? [specifiedServiceName] : appServices;
|
|
52
63
|
for (const folderName of serviceNames) {
|
|
53
64
|
try {
|
|
54
65
|
processConfig(folderName, appName);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"synth.js","sourceRoot":"","sources":["../../../src/commands/synth.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"synth.js","sourceRoot":"","sources":["../../../src/commands/synth.ts"],"names":[],"mappings":"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","sourcesContent":["// `qpq synth [service]` — synthesizes each backend service's QPQ config to\n// dist/apps/<app>/infrastructure/<module>-config.json.\n//\n// Runs with ts-node hooks registered (see runCli), which transpiles each\n// service's infrastructure.ts on require. Cross-package `@scope/*` imports\n// resolve through the workspace node_modules symlinks to already-built dist.\nimport { qpqCoreUtils } from 'quidproquo-core';\n\nimport fs from 'fs';\nimport path from 'path';\n\nimport { getPositionalArgs } from '../lib/args';\nimport { primeDeployEnvFromConfig } from '../lib/deployEnv';\nimport { getAvailableApps, getRoot, getServiceNamesWithSubdir } from '../lib/discovery';\nimport { loadServiceQpqConfig } from '../lib/qpqConfigs';\nimport { resolveAppSelection } from '../lib/resolveAppSelection';\n\nconst processConfig = (folderName: string, appName: string): void => {\n console.log(`Processing infrastructure: [${folderName}] for app [${appName}]`);\n const qpqConfig = loadServiceQpqConfig(appName, folderName);\n const moduleName = qpqCoreUtils.getApplicationModuleName(qpqConfig);\n\n const directoryPath = path.join(getRoot(), 'dist', 'apps', appName, 'infrastructure');\n fs.mkdirSync(directoryPath, { recursive: true });\n fs.writeFileSync(path.join(directoryPath, `${moduleName}-config.json`), JSON.stringify(qpqConfig, null, 2));\n console.log(` -> ${appName}/infrastructure/${moduleName}-config.json`);\n};\n\nexport const synthCommand = async (argv: string[]): Promise<void> => {\n const [specifiedServiceName] = getPositionalArgs(argv, ['--app', '--env']);\n\n const hasExplicitApp =\n argv.includes('--app') || argv.some((a) => a.startsWith('--app=')) || !!process.env.npm_config_app || !!process.env.DEPLOY_APP_NAME;\n\n let appNames: string[];\n if (specifiedServiceName && !hasExplicitApp) {\n // A bare service name is unambiguous — synth it in whichever app owns it.\n const appWithService = getAvailableApps().find((appName) => getServiceNamesWithSubdir(appName, 'service').includes(specifiedServiceName));\n if (!appWithService) {\n console.error(`Service '${specifiedServiceName}' not found in any app`);\n process.exit(1);\n }\n appNames = [appWithService];\n } else {\n const selection = await resolveAppSelection({\n argv,\n envVar: 'DEPLOY_APP_NAME',\n allowAll: true,\n });\n appNames = selection === 'all' ? getAvailableApps() : [selection];\n }\n\n console.log(`QPQ synthesizing apps: ${appNames.join(', ')}`);\n\n for (const appName of appNames) {\n // Service configs read ENVIRONMENT / AWS_DEFAULT_* at require time. When\n // invoked inside a deploy they're already primed; standalone synth primes\n // them from deploy.config.json (development default).\n primeDeployEnvFromConfig(appName);\n\n // Validate a specified service against the app's discovered services before it\n // reaches loadServiceQpqConfig -> require. The bare-service-name branch above\n // already checks this; the --app/env branch used to skip it, letting a typo hit\n // a cryptic module-resolution error and a `../` value normalize into an arbitrary\n // require target. Both paths now validate identically.\n const appServices = getServiceNamesWithSubdir(appName, 'service');\n if (specifiedServiceName && !appServices.includes(specifiedServiceName)) {\n console.error(`Service '${specifiedServiceName}' not found in app '${appName}'`);\n process.exitCode = 1;\n continue;\n }\n\n const serviceNames = specifiedServiceName ? [specifiedServiceName] : appServices;\n\n for (const folderName of serviceNames) {\n try {\n processConfig(folderName, appName);\n } catch (error) {\n console.error(`Failed to process ${folderName} in ${appName}:`, error);\n process.exitCode = 1;\n }\n }\n }\n};\n"]}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Source-level circular import detection over the consumer repo's npm
|
|
2
|
+
// workspaces, powered by madge (AST-based dependency graph + cycle detection).
|
|
3
|
+
// Complements the rspack CircularCheckRspackPlugin (which needs a bundle to
|
|
4
|
+
// run): this scans TypeScript sources directly, so it can run inside tsc-only
|
|
5
|
+
// flows like `npm run validate-ts` with no bundling.
|
|
6
|
+
//
|
|
7
|
+
// Scope: each workspace's src, relative imports. Cross-package cycles are
|
|
8
|
+
// already impossible — TypeScript project references refuse to build them — so
|
|
9
|
+
// every runtime-relevant cycle lives inside one package's src. Type-only
|
|
10
|
+
// imports are skipped (skipTypeImports): tsc erases them, so they never create
|
|
11
|
+
// a runtime cycle.
|
|
12
|
+
import fs from 'fs';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
// madge ships no type definitions; declare the narrow slice we use.
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
16
|
+
const madge = require('madge');
|
|
17
|
+
// Expand npm workspace globs (plain path segments and `*` segments only — the
|
|
18
|
+
// only forms npm workspaces use in practice) into existing directories.
|
|
19
|
+
const expandWorkspaceGlob = (root, pattern) => {
|
|
20
|
+
let candidates = [root];
|
|
21
|
+
for (const segment of pattern.split('/')) {
|
|
22
|
+
if (segment === '*') {
|
|
23
|
+
candidates = candidates.flatMap((dir) => fs.existsSync(dir)
|
|
24
|
+
? fs
|
|
25
|
+
.readdirSync(dir, { withFileTypes: true })
|
|
26
|
+
.filter((entry) => entry.isDirectory())
|
|
27
|
+
.map((entry) => path.join(dir, entry.name))
|
|
28
|
+
: []);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
candidates = candidates.map((dir) => path.join(dir, segment));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return candidates.filter((dir) => fs.existsSync(dir) && fs.statSync(dir).isDirectory());
|
|
35
|
+
};
|
|
36
|
+
export const getWorkspaceDirectories = (root) => {
|
|
37
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
38
|
+
const patterns = packageJson.workspaces ?? [];
|
|
39
|
+
return patterns.flatMap((pattern) => expandWorkspaceGlob(root, pattern));
|
|
40
|
+
};
|
|
41
|
+
export const findWorkspaceImportCycles = async (root) => {
|
|
42
|
+
const sourceDirs = getWorkspaceDirectories(root)
|
|
43
|
+
.map((dir) => path.join(dir, 'src'))
|
|
44
|
+
.filter((dir) => fs.existsSync(dir));
|
|
45
|
+
// Excludes: node_modules and built output (dist/lib), declaration files
|
|
46
|
+
// (type-only, can't cycle at runtime), and anything madge resolves to outside
|
|
47
|
+
// the repo root (linked framework packages — their cycles surface through the
|
|
48
|
+
// rspack CircularCheckRspackPlugin instead, this command owns the consumer
|
|
49
|
+
// repo). Out-of-root paths start with '..' because baseDir is the repo root.
|
|
50
|
+
const result = await madge(sourceDirs, {
|
|
51
|
+
baseDir: root,
|
|
52
|
+
fileExtensions: ['ts', 'tsx'],
|
|
53
|
+
excludeRegExp: [/node_modules/, /(^|\/)(dist|lib)\//, /\.d\.ts$/, /^\.\./],
|
|
54
|
+
detectiveOptions: {
|
|
55
|
+
ts: { skipTypeImports: true },
|
|
56
|
+
tsx: { skipTypeImports: true },
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
return result.circular();
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=circularImports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circularImports.js","sourceRoot":"","sources":["../../../src/lib/circularImports.ts"],"names":[],"mappings":"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","sourcesContent":["// Source-level circular import detection over the consumer repo's npm\n// workspaces, powered by madge (AST-based dependency graph + cycle detection).\n// Complements the rspack CircularCheckRspackPlugin (which needs a bundle to\n// run): this scans TypeScript sources directly, so it can run inside tsc-only\n// flows like `npm run validate-ts` with no bundling.\n//\n// Scope: each workspace's src, relative imports. Cross-package cycles are\n// already impossible — TypeScript project references refuse to build them — so\n// every runtime-relevant cycle lives inside one package's src. Type-only\n// imports are skipped (skipTypeImports): tsc erases them, so they never create\n// a runtime cycle.\nimport fs from 'fs';\nimport path from 'path';\n\n// madge ships no type definitions; declare the narrow slice we use.\n// eslint-disable-next-line @typescript-eslint/no-require-imports\nconst madge = require('madge') as (paths: string[], config: object) => Promise<{ circular(): string[][] }>;\n\nexport type ImportCycle = string[];\n\n// Expand npm workspace globs (plain path segments and `*` segments only — the\n// only forms npm workspaces use in practice) into existing directories.\nconst expandWorkspaceGlob = (root: string, pattern: string): string[] => {\n let candidates = [root];\n\n for (const segment of pattern.split('/')) {\n if (segment === '*') {\n candidates = candidates.flatMap((dir) =>\n fs.existsSync(dir)\n ? fs\n .readdirSync(dir, { withFileTypes: true })\n .filter((entry) => entry.isDirectory())\n .map((entry) => path.join(dir, entry.name))\n : [],\n );\n } else {\n candidates = candidates.map((dir) => path.join(dir, segment));\n }\n }\n\n return candidates.filter((dir) => fs.existsSync(dir) && fs.statSync(dir).isDirectory());\n};\n\nexport const getWorkspaceDirectories = (root: string): string[] => {\n const packageJson = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));\n const patterns: string[] = packageJson.workspaces ?? [];\n return patterns.flatMap((pattern) => expandWorkspaceGlob(root, pattern));\n};\n\nexport const findWorkspaceImportCycles = async (root: string): Promise<ImportCycle[]> => {\n const sourceDirs = getWorkspaceDirectories(root)\n .map((dir) => path.join(dir, 'src'))\n .filter((dir) => fs.existsSync(dir));\n\n // Excludes: node_modules and built output (dist/lib), declaration files\n // (type-only, can't cycle at runtime), and anything madge resolves to outside\n // the repo root (linked framework packages — their cycles surface through the\n // rspack CircularCheckRspackPlugin instead, this command owns the consumer\n // repo). Out-of-root paths start with '..' because baseDir is the repo root.\n const result = await madge(sourceDirs, {\n baseDir: root,\n fileExtensions: ['ts', 'tsx'],\n excludeRegExp: [/node_modules/, /(^|\\/)(dist|lib)\\//, /\\.d\\.ts$/, /^\\.\\./],\n detectiveOptions: {\n ts: { skipTypeImports: true },\n tsx: { skipTypeImports: true },\n },\n });\n\n return result.circular();\n};\n"]}
|
|
@@ -4,6 +4,7 @@ export type RunCommandOptions = {
|
|
|
4
4
|
logCommand?: boolean;
|
|
5
5
|
};
|
|
6
6
|
export declare const runCommand: (command: string, args: string[], options?: RunCommandOptions) => Promise<void>;
|
|
7
|
+
export declare const runCommandBestEffort: (command: string, args: string[], options?: RunCommandOptions) => Promise<void>;
|
|
7
8
|
export type RunCommandPrefixedOptions = {
|
|
8
9
|
env?: Record<string, string>;
|
|
9
10
|
cwd?: string;
|
|
@@ -8,7 +8,11 @@ export const runCommand = (command, args, options = {}) => new Promise((resolve,
|
|
|
8
8
|
}
|
|
9
9
|
const child = spawn(command, validArgs, {
|
|
10
10
|
stdio: 'inherit',
|
|
11
|
-
|
|
11
|
+
// Shell only on Windows (to resolve npm/aws/cdk .cmd shims). On posix, run
|
|
12
|
+
// without a shell so the already-array args are passed straight to the
|
|
13
|
+
// program and can't be re-interpreted by `sh -c` — no command injection via
|
|
14
|
+
// interpolated values (stack names, CI-supplied env, etc.).
|
|
15
|
+
shell: process.platform === 'win32',
|
|
12
16
|
cwd: options.cwd ?? process.cwd(),
|
|
13
17
|
env: { ...process.env, ...(options.env ?? {}) },
|
|
14
18
|
});
|
|
@@ -21,6 +25,21 @@ export const runCommand = (command, args, options = {}) => new Promise((resolve,
|
|
|
21
25
|
return resolve();
|
|
22
26
|
});
|
|
23
27
|
});
|
|
28
|
+
// Run a command for its side effect only, swallowing both its output and its
|
|
29
|
+
// exit code — for best-effort cleanup steps (e.g. `docker rm -f` of a container
|
|
30
|
+
// that may not exist) that must never fail the run. Without a shell there's no
|
|
31
|
+
// `>/dev/null 2>&1 || true`, so quieting and non-failing happen here instead.
|
|
32
|
+
export const runCommandBestEffort = (command, args, options = {}) => new Promise((resolve) => {
|
|
33
|
+
const validArgs = args.filter((a) => !!a);
|
|
34
|
+
const child = spawn(command, validArgs, {
|
|
35
|
+
stdio: 'ignore',
|
|
36
|
+
shell: process.platform === 'win32',
|
|
37
|
+
cwd: options.cwd ?? process.cwd(),
|
|
38
|
+
env: { ...process.env, ...(options.env ?? {}) },
|
|
39
|
+
});
|
|
40
|
+
child.on('error', () => resolve());
|
|
41
|
+
child.on('exit', () => resolve());
|
|
42
|
+
});
|
|
24
43
|
const PREFIX_COLORS = [36, 32, 33, 35, 34, 96, 92, 93, 95, 94];
|
|
25
44
|
let colorIndex = 0;
|
|
26
45
|
// Hand each concurrent task a distinct prefix color so interleaved output is
|
|
@@ -38,7 +57,11 @@ export const runCommandPrefixed = (label, command, args, options = {}) => new Pr
|
|
|
38
57
|
const prefix = `\x1b[${options.color ?? 36}m[${label}]\x1b[0m `;
|
|
39
58
|
const child = spawn(command, validArgs, {
|
|
40
59
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
41
|
-
|
|
60
|
+
// Shell only on Windows (to resolve npm/aws/cdk .cmd shims). On posix, run
|
|
61
|
+
// without a shell so the already-array args are passed straight to the
|
|
62
|
+
// program and can't be re-interpreted by `sh -c` — no command injection via
|
|
63
|
+
// interpolated values (stack names, CI-supplied env, etc.).
|
|
64
|
+
shell: process.platform === 'win32',
|
|
42
65
|
cwd: options.cwd ?? process.cwd(),
|
|
43
66
|
env: { ...process.env, ...(options.env ?? {}) },
|
|
44
67
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runCommand.js","sourceRoot":"","sources":["../../../src/lib/runCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAYtC,2EAA2E;AAC3E,kDAAkD;AAClD,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,OAAe,EAAE,IAAc,EAAE,UAA6B,EAAE,EAAiB,EAAE,CAC5G,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE1C,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,oBAAoB,OAAO,IAAI,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE;QACtC,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"runCommand.js","sourceRoot":"","sources":["../../../src/lib/runCommand.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from 'child_process';\nimport type { Readable } from 'stream';\n\nexport type RunCommandOptions = {\n // Extra environment variables merged over the parent process env.\n env?: Record<string, string>;\n // Working directory for the child (defaults to cwd).\n cwd?: string;\n // Echo the command before running it.\n logCommand?: boolean;\n};\n\n// Spawn a command, inheriting stdio, resolving on success. A non-zero exit\n// REJECTS so a failed build/deploy stops the run.\nexport const runCommand = (command: string, args: string[], options: RunCommandOptions = {}): Promise<void> =>\n new Promise((resolve, reject) => {\n const validArgs = args.filter((a) => !!a);\n\n if (options.logCommand) {\n console.log(`Running command: ${command} ${validArgs.join(' ')}`);\n }\n\n const child = spawn(command, validArgs, {\n stdio: 'inherit',\n // Shell only on Windows (to resolve npm/aws/cdk .cmd shims). On posix, run\n // without a shell so the already-array args are passed straight to the\n // program and can't be re-interpreted by `sh -c` — no command injection via\n // interpolated values (stack names, CI-supplied env, etc.).\n shell: process.platform === 'win32',\n cwd: options.cwd ?? process.cwd(),\n env: { ...process.env, ...(options.env ?? {}) },\n });\n\n child.on('error', (error) => reject(error));\n\n child.on('exit', (code, signal) => {\n if (signal) return reject(new Error(`${command} was killed with signal ${signal}`));\n if (code) return reject(new Error(`${command} ${validArgs.join(' ')} exited with code ${code}`));\n return resolve();\n });\n });\n\n// Run a command for its side effect only, swallowing both its output and its\n// exit code — for best-effort cleanup steps (e.g. `docker rm -f` of a container\n// that may not exist) that must never fail the run. Without a shell there's no\n// `>/dev/null 2>&1 || true`, so quieting and non-failing happen here instead.\nexport const runCommandBestEffort = (command: string, args: string[], options: RunCommandOptions = {}): Promise<void> =>\n new Promise((resolve) => {\n const validArgs = args.filter((a) => !!a);\n\n const child = spawn(command, validArgs, {\n stdio: 'ignore',\n shell: process.platform === 'win32',\n cwd: options.cwd ?? process.cwd(),\n env: { ...process.env, ...(options.env ?? {}) },\n });\n\n child.on('error', () => resolve());\n child.on('exit', () => resolve());\n });\n\nexport type RunCommandPrefixedOptions = {\n env?: Record<string, string>;\n cwd?: string;\n // ANSI color code for the prefix (see nextPrefixColor).\n color?: number;\n};\n\nconst PREFIX_COLORS = [36, 32, 33, 35, 34, 96, 92, 93, 95, 94];\nlet colorIndex = 0;\n\n// Hand each concurrent task a distinct prefix color so interleaved output is\n// scannable.\nexport const nextPrefixColor = (): number => {\n const color = PREFIX_COLORS[colorIndex % PREFIX_COLORS.length];\n colorIndex += 1;\n return color;\n};\n\n// Like runCommand, but pipes output and prefixes every line with a colored\n// [label] — for running many commands concurrently without unreadable\n// interleaving. Rejects on non-zero exit.\nexport const runCommandPrefixed = (label: string, command: string, args: string[], options: RunCommandPrefixedOptions = {}): Promise<void> =>\n new Promise((resolve, reject) => {\n const validArgs = args.filter((a) => !!a);\n const prefix = `\\x1b[${options.color ?? 36}m[${label}]\\x1b[0m `;\n\n const child = spawn(command, validArgs, {\n stdio: ['ignore', 'pipe', 'pipe'],\n // Shell only on Windows (to resolve npm/aws/cdk .cmd shims). On posix, run\n // without a shell so the already-array args are passed straight to the\n // program and can't be re-interpreted by `sh -c` — no command injection via\n // interpolated values (stack names, CI-supplied env, etc.).\n shell: process.platform === 'win32',\n cwd: options.cwd ?? process.cwd(),\n env: { ...process.env, ...(options.env ?? {}) },\n });\n\n const attach = (stream: Readable, out: NodeJS.WriteStream): void => {\n let buffered = '';\n stream.on('data', (chunk: Buffer) => {\n buffered += chunk.toString();\n const lines = buffered.split('\\n');\n buffered = lines.pop() ?? '';\n lines.forEach((line) => out.write(`${prefix}${line}\\n`));\n });\n stream.on('end', () => {\n if (buffered) out.write(`${prefix}${buffered}\\n`);\n });\n };\n\n attach(child.stdout as Readable, process.stdout);\n attach(child.stderr as Readable, process.stderr);\n\n child.on('error', (error) => reject(error));\n\n child.on('exit', (code, signal) => {\n if (signal) return reject(new Error(`[${label}] ${command} was killed with signal ${signal}`));\n if (code) return reject(new Error(`[${label}] ${command} exited with code ${code}`));\n return resolve();\n });\n });\n"]}
|